Статьи

iOS лаконично — управление активами

Теперь, когда у нас есть общее представление об управлении сценами iOS, следующая важная тема, которую необходимо решить, — это управление мультимедийными активами в приложении. Приложения iOS хранят свои активы, используя ту же иерархическую файловую систему, что и любая другая современная операционная система. Текстовые, графические, аудио- и видеофайлы организованы в папки и доступны с использованием привычных путей к файлам, таких как Documents / SomePicture.png.

В этой главе мы узнаем о стандартной файловой структуре приложения; как добавить ресурсы в проект; и как найти, загрузить и сохранить файлы. Мы также поговорим о необходимых ресурсах для всех приложений iOS.

На протяжении всей главы мы будем говорить о файлах и папках, но помните, что файловая система должна быть полностью скрыта от пользователей iOS. Вместо того, чтобы показывать пользователям файлы и папки за приложением, iOS рекомендует разработчикам представлять файловую систему как ориентированные на пользователя документы. Например, в приложении для создания эскизов рисунки должны быть перечислены с семантическими отображаемыми именами и организованы в альбомы для рисования или аналогичную абстрактную организационную структуру. Вы никогда не должны показывать пути к пользовательским файлам, такие как sketchbook-1 / your-drawing.svg.


Файловая система iOS была разработана с учетом требований безопасности. Вместо того, чтобы позволить приложению получать доступ ко всей файловой системе устройства, iOS предоставляет каждому приложению свою собственную отдельную файловую систему (песочницу). Это означает, что ваше приложение не имеет доступа к файлам, созданным другими приложениями. Если вам необходим доступ к информации, которая не принадлежит вашему приложению (например, список контактов пользователя), вы запрашиваете ее у посредника (например, из Address Book Framework) вместо прямого доступа к файлам.

Песочница — это мини-файловая система, предназначенная исключительно для работы вашего приложения. Все приложения используют каноническую файловую структуру, состоящую из четырех каталогов верхнего уровня, в каждом из которых хранится файл определенного типа.

  • AppName.app , пакет приложений, который содержит исполняемый файл вашего приложения и все его необходимые медиаресурсы. Вы можете читать из этой папки, но вы никогда не должны писать в нее. В следующем разделе обсуждаются комплекты более подробно.
  • Documents / , папка для пользовательского контента и других важных файлов данных, которые не могут быть воссозданы вашим приложением. Содержимое этого каталога доступно через iCloud.
  • Library / , папка для файлов приложений, которые не используются пользователем, но должны сохраняться между запусками.
  • tmp / , папка для временных файлов, используемых во время работы вашего приложения. Файлы в этой папке не обязательно сохраняются между запусками приложения. iOS автоматически удалит временные файлы, когда это необходимо, пока ваше приложение не запущено, но вы должны вручную удалить временные файлы, как только вы закончите с ними, в качестве рекомендации.

Когда пользователь устанавливает приложение, создается новая песочница, содержащая все эти папки. После этого ваше приложение может динамически создавать произвольные подкаталоги в любой из этих папок верхнего уровня. Есть также несколько предопределенных подкаталогов, как описано в следующем списке.

  • Библиотека / Поддержка приложений / , папка для файлов поддержки, которую можно при необходимости создать заново. Это включает в себя загруженный и сгенерированный контент. Вы должны использовать расширенный атрибут com.apple.MobileBackup, чтобы предотвратить резервное копирование этой папки.
  • Библиотека / Cache / , папка для файлов кеша. Эти файлы могут быть удалены без уведомления, поэтому ваше приложение должно иметь возможность воссоздать их изящно. Эта папка также является подходящим местом для хранения загруженного контента.

Важно поместить файлы в соответствующую папку, чтобы обеспечить правильное резервное копирование, не занимая ненужного места на устройстве пользователя. iTunes автоматически создает резервные копии файлов в папках Documents / и Library / (за исключением Library / Cache /). Ни пакет приложений, ни папка tmp / никогда не нуждаются в резервном копировании.

Приложение для iOS — это не просто исполняемый файл. Он также содержит медиа, файлы данных и, возможно, локализованный текст для разных регионов. Чтобы упростить развертывание, XCode упаковывает исполняемый файл и все его необходимые файлы в специальную папку, называемую комплектом приложений. Несмотря на то, что это папка, пакет приложений использует расширение .app. Вы можете рассматривать пакет приложений как ZIP-файл, который запускает приложение при его открытии.

Поскольку ваш пакет приложений содержит все ваши медиаресурсы, вам нужно взаимодействовать с ним во время работы вашей программы. Класс NSBundle облегчает поиск в вашем приложении определенных файлов, которые затем могут быть загружены другими классами. Например, вы можете найти определенный файл изображения с помощью NSBundle, а затем добавить его в представление с помощью класса UIImage. Мы сделаем это в другом разделе «Комплект приложений».


В этой главе используется простое приложение для изучения некоторых основных методов доступа к файлам в iOS. Сначала откройте Xcode, создайте новый проект и выберите Single View Application для шаблона.

tutorial_image
Рисунок 81: Создание нового приложения Single View

Используйте AssetManagement для названия продукта, edu.self для идентификатора компании и убедитесь, что выбраны Использовать раскадровки и Использовать автоматический подсчет ссылок.

tutorial_image
Рисунок 82: Настройка нового проекта

Вы можете сохранить проект где угодно.


Прежде чем мы перейдем к мультимедийным ресурсам приложения, мы рассмотрим основные инструменты для доступа к файловой системе. В следующих разделах обсуждается, как создавать пути к файлам, создавать простые текстовые файлы и загружать их обратно в приложение.

Одной из наиболее распространенных задач файловой системы является создание пути к конкретному ресурсу. Но прежде чем вы сможете получить доступ к какому-либо файлу, вам нужно найти путь к изолированной программной среде приложения или к одной из папок верхнего уровня, которые обсуждались ранее. Самый простой способ сделать это — использовать глобальную функцию NSHomeDirectory (), которая возвращает абсолютный путь к изолированной программной среде приложения. Например, попробуйте изменить метод viewDidLoad для ViewController.m следующим образом:

1
2
3
4
5
— (void)viewDidLoad {
    [super viewDidLoad];
    NSString *sandboxPath = NSHomeDirectory();
    NSLog(@»The app sandbox resides at: %@», sandboxPath);
}

Когда приложение загружается в iOS Simulator, вы должны увидеть что-то вроде следующего на панели вывода Xcode.

1
/Users/ryan/Library/Application Support/iPhone Simulator/6.0/Applications/9E38D1C4-8B11-4599-88BE-CD9E36C21A41

Этот путь представляет корень вашего приложения. Если вы перейдете к этому каталогу в терминале, вы найдете следующие четыре каталога.

1
2
3
4
AssetManagement.app
Documents/
Library/
tmp/

Не удивительно, что это каноническая файловая структура, обсужденная ранее. Конечно, NSHomeDirectory () будет возвращать другой путь, когда ваше приложение работает на устройстве iOS. Идея использования NSHomeDirectory () вместо ручной генерации пути к вашему приложению состоит в том, чтобы всегда иметь правильный корневой путь, независимо от того, где находится ваше приложение.

Связанная функция NSTeilitaryDirectory () возвращает путь к каталогу tmp /. Для других стандартных папок приложения вам необходимо использовать класс NSFileManager.

1
2
3
4
5
6
7
8
9
— (void)viewDidLoad {
    [super viewDidLoad];
    NSFileManager *sharedFM = [NSFileManager defaultManager];
    NSArray *paths = [sharedFM URLsForDirectory:NSLibraryDirectory
                                      inDomains:NSUserDomainMask];
    if ([paths count] > 0) {
        NSLog(@»The Library subfolder: %@», paths[0]);
    }
}

Как видите, NSFileManager реализован как одноэлементный, и к общему экземпляру следует обращаться через метод класса defaultManager. Перечисление NSSearchPathDirectory определяет несколько констант, которые представляют стандартные местоположения, используемые приложениями OS X и iOS. Некоторые из этих расположений (например, NSDesktopDirectory) не применимы в приложениях для iOS, однако метод URLsForDirectory: inDomains: будет по-прежнему возвращать соответствующую подпапку в изолированной программной среде приложения. Константы для каталогов, которые мы обсуждали, перечислены ниже.

1
2
3
4
NSDocumentDirectory /* Documents/ */
NSLibraryDirectory /* Library/ */
NSCachesDirectory /* Library/Caches */
NSApplicationSupportDirectory /* Library/Application Support/ */

Метод URLsForDirectory: inDomains: возвращает NSArray, содержащий объекты NSURL, который является объектно-ориентированным представлением пути к файлу.

Если у вас есть местоположение одного из стандартных каталогов, вы можете вручную собрать путь к определенному файлу, используя методы экземпляра NSURL. Обратите внимание, что NSString также предоставляет связанные утилиты, но NSURL является предпочтительным способом представления путей к файлам.

Например, URLByAppendingPathComponent: метод обеспечивает простой способ создания пути к определенному файлу. Следующий фрагмент создает путь к файлу с именем someData.txt в каталоге Library / приложения.

01
02
03
04
05
06
07
08
09
10
11
12
— (void)viewDidLoad {
    [super viewDidLoad];
    NSFileManager *sharedFM = [NSFileManager defaultManager];
    NSArray *paths = [sharedFM URLsForDirectory:NSLibraryDirectory
                                      inDomains:NSUserDomainMask];
    if ([paths count] > 0) {
        NSURL *libraryPath = paths[0];
        NSURL *appDataPath = [libraryPath
                              URLByAppendingPathComponent:@»someData.txt»];
        NSLog(@»%@», appDataPath);
    }
}

Несколько других полезных методов экземпляра NSURL описаны в следующем списке. Вместе они предоставляют базовую функциональность для навигации по файловой иерархии и ручного определения имен и типов файлов.

  • URLByDeletingLastPathComponent возвращает новый NSURL, представляющий родительскую папку пути получения.
  • lastPathComponent возвращает последний компонент в пути в виде строки. Это может быть либо имя папки, либо имя файла, в зависимости от пути.
  • pathExtension возвращает расширение файла пути в виде строки. Если путь не содержит точку, он возвращает пустую строку, в противном случае он возвращает последнюю группу символов, следующих за точкой.
  • pathComponents разбивает путь на его составные части и возвращает их как NSArray .

Важно понимать, что NSURL описывает только местоположение ресурса. Он не представляет сам файл или папку. Чтобы получить данные файла, вам нужен какой-то способ их интерпретации. Класс NSData предоставляет низкоуровневый API для чтения в необработанных байтах, но большую часть времени вы захотите использовать высокоуровневый интерфейс для интерпретации содержимого файла.

Платформы iOS включают в себя множество классов для сохранения и загрузки различных типов файлов. Например, NSString может читать и записывать текстовые файлы, UIImage может отображать изображения внутри представления, а AVAudioPlayer может воспроизводить музыку, загруженную из файла. Мы посмотрим на UIImage, как только доберемся до комплекта приложения, но сейчас давайте придерживаться основных манипуляций с текстовыми файлами.

Чтобы сохранить файл с помощью NSString, используйте writeToURL: автоматически: кодировка: ошибка: метод. Первый аргумент — это NSURL, представляющий путь к файлу, второй определяет, сохранять ли его сначала во вспомогательный файл или нет, а третий — одна из констант, определенных перечислением NSStringEncoding , а аргумент error — ссылка на NSError. экземпляр, который будет записывать подробности ошибки в случае сбоя метода. Следующий фрагмент демонстрирует writeToURL: автоматически: кодировка: ошибка: путем создания простого текстового файла с именем someData.txt в папке Library / .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
— (void)viewDidLoad {
    [super viewDidLoad];
    NSFileManager *sharedFM = [NSFileManager defaultManager];
    NSArray *paths = [sharedFM URLsForDirectory:NSLibraryDirectory
                                      inDomains:NSUserDomainMask];
    if ([paths count] > 0) {
        NSURL *libraryPath = paths[0];
        NSURL *appDataPath = [libraryPath
                              URLByAppendingPathComponent:@»someData.txt»];
         
        NSString *someAppData = @»Hello, World! This is a file I created dynamically»;
        NSError *error = nil;
        BOOL success = [someAppData writeToURL:appDataPath
                                     atomically:YES
                                       encoding:NSUnicodeStringEncoding
                                          error:&error];
        if (success) {
            NSLog(@»Wrote some data to %@», appDataPath);
        } else {
            NSLog(@»Could not write data to file. Error: %@», error);
        }
    }
}

При сохранении или загрузке текстовых файлов обязательно указывайте кодировку файла, в противном случае ваши текстовые данные могут быть неожиданно изменены при записи или чтении файла. Несколько общих констант кодирования включены сюда.

1
2
3
NSASCIIStringEncoding–7-bit ASCII encoding with 8-bit chars (ASCII values 0-127).
NSISOLatin1StringEncoding–8-bit ISO Latin 1 encoding.
NSUnicodeStringEncoding–Unicode encoding.

В случае сомнений, вы, вероятно, захотите использовать NSUnicodeStringEncoding, чтобы убедиться, что многобайтовые символы интерпретируются правильно.

Чтобы загрузить текстовый файл, вы можете использовать связанную строкуWithContentsOfURL: encoding: error:. Это работает почти так же, как writeToURL: автоматически: кодировка: ошибка: но оно реализовано как метод класса, а не как метод экземпляра. В следующем примере текстовый файл, созданный предыдущим фрагментом, загружается обратно в приложение.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
— (void)viewDidLoad {
    [super viewDidLoad];
    NSFileManager *sharedFM = [NSFileManager defaultManager];
    NSArray *paths = [sharedFM URLsForDirectory:NSLibraryDirectory
                                      inDomains:NSUserDomainMask];
    if ([paths count] > 0) {
        NSURL *libraryPath = paths[0];
        NSURL *appDataPath = [libraryPath
                              URLByAppendingPathComponent:@»someData.txt»];
         
        NSError *error = nil;
        NSString *loadedText = [NSString
                                stringWithContentsOfURL:appDataPath
                                encoding:NSUnicodeStringEncoding
                                error:&error];
        if (loadedText != nil) {
            NSLog(@»Successfully loaded text: %@», loadedText);
        } else {
            NSLog(@»Could not load data from file. Error: %@», error);
        }
    }
}

В реальном мире вы, вероятно, сохраните и загрузите данные, которые были сгенерированы динамически, а не жестко закодированы в виде буквенной строки. Например, вы можете сохранить предпочтения шаблона или информацию о пользователе, которая должна сохраняться между запусками приложения, в текстовом файле. Вполне возможно вручную загрузить и интерпретировать эти данные из простого текста, но имейте в виду, что есть несколько встроенных инструментов для работы и хранения структурированных данных или даже целых объектов Objective-C. Например, NSDictionary определяет метод DictionaryWithContentsOfURL: загружает XML-файл, содержащий пары ключ-значение.

Методы NSString, описанные ранее, объединяют создание файла и запись содержимого в один шаг, но для создания каталогов нам необходимо вернуться к классу NSFileManager. Он определяет несколько методов, которые позволяют вам изменять содержимое каталога.

CreateDirectoryAtURL: withIntermediateDirectories: attribute: error: метод экземпляра создает новый каталог по указанному пути. Второй аргумент — это логическое значение, которое определяет, следует ли создавать промежуточные каталоги автоматически, атрибуты позволяют вам определить атрибуты файла для нового каталога, а последний аргумент — это ссылка на экземпляр NSError, который будет содержать подробности ошибки в случае, если метод провал.

Например, если ваше приложение использует пользовательские шаблоны, загруженные с сервера, вы можете сохранить их в Library / Templates / . Чтобы создать эту папку, вы можете использовать что-то вроде следующего.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
— (void)viewDidLoad {
    [super viewDidLoad];
    NSFileManager *sharedFM = [NSFileManager defaultManager];
    NSArray *paths = [sharedFM URLsForDirectory:NSLibraryDirectory
                                      inDomains:NSUserDomainMask];
    if ([paths count] > 0) {
        NSURL *libraryPath = paths[0];
        NSURL *templatesPath = [libraryPath
                                URLByAppendingPathComponent:@»Templates»];
         
        NSError *error = nil;
        BOOL success = [sharedFM createDirectoryAtURL:templatesPath
                          withIntermediateDirectories:YES
                                           attributes:nil
                                                error:&error];
        if (success) {
            NSLog(@»Successfully created a directory at %@»,
                  templatesPath);
        } else {
            NSLog(@»Could not create the directory. Error: %@», error);
        }
    }
}

Если оставить для атрибута аргумент nil, метод должен использовать группу по умолчанию, владельца и разрешения для текущего процесса.

Класс NSFileManager также можно использовать для перемещения или переименования файлов и папок с помощью метода moveItemAtURL: toURL: error: instance. Работает следующим образом.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
— (void)viewDidLoad {
    [super viewDidLoad];
    NSFileManager *sharedFM = [NSFileManager defaultManager];
    NSArray *paths = [sharedFM URLsForDirectory:NSLibraryDirectory
                                      inDomains:NSUserDomainMask];
    if ([paths count] > 0) {
        NSURL *libraryPath = paths[0];
        NSURL *sourcePath = [libraryPath
                             URLByAppendingPathComponent:@»someData.txt»];
        NSURL *destinationPath = [libraryPath
                        URLByAppendingPathComponent:@»someOtherData.txt»];
         
        NSError *error = nil;
        BOOL success = [sharedFM moveItemAtURL:sourcePath
                                         toURL:destinationPath
                                         error:&error];
        if (success) {
            NSLog(@»Successfully moved %@ to %@»,
                  sourcePath,
                  destinationPath);
        } else {
            NSLog(@»Could not move the file. Error: %@», error);
        }
    }
}

Это переименовывает файл someData.txt, который мы создали ранее, в someOtherData.txt . Если вам нужно скопировать файлы, вы можете использовать copyItemAtURL: toURL: error:, который работает так же, но оставляет исходный файл без изменений.

Наконец, NSFileManager метод removeItemAtURL: error: позволяет вам удалять файлы или папки. Просто передайте экземпляр NSURL, содержащий путь, который вы хотите удалить, следующим образом.

1
[sharedFM removeItemAtURL:targetURL error:&error];

Если targetURL является каталогом, его содержимое будет рекурсивно удалено.

Также можно перечислить файлы и подкаталоги в папке, используя метод enumeratorAtPath: NSFileManager. Это возвращает объект NSDirectoryEnumerator, который вы можете использовать для перебора каждого файла или папки. Например, вы можете перечислить содержимое каталога Documents / верхнего уровня следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
— (void)viewDidLoad {
    [super viewDidLoad];
    NSFileManager *sharedFM = [NSFileManager defaultManager];
    NSArray *paths = [sharedFM URLsForDirectory:NSDocumentDirectory
                                      inDomains:NSUserDomainMask];
    if ([paths count] > 0) {
        NSString *documentsPath = [paths[0] path];
        NSLog(@»%@», documentsPath);
        NSDirectoryEnumerator *enumerator = [sharedFM enumeratorAtPath:documentsPath];
        id object;
        while(object = [enumerator nextObject]) {
            NSLog(@»%@», object);
        }
    }
}

Обратите внимание, что этот перечислитель будет перебирать все подкаталоги. Вы можете изменить это поведение, вызвав метод skipDescendents в экземпляре NSDirectoryEnumerator или используя более сложный enumeratorAtURL: includesPropertiesForKeys: options: errorHandler: метод NSFileManager.


Обсуждаемые ранее методы доступа к файлам обычно используются только для взаимодействия с файлами, которые динамически создаются во время выполнения. Стандартные папки Library /, Documents / и tmp / являются локальными для устройства, на котором установлено приложение, и они изначально пусты. Для ресурсов, которые являются неотъемлемой частью самого приложения (в отличие от создания приложения), нам нужен другой инструмент — пакет приложений.

Комплект приложений представляет весь ваш проект, который состоит из исполняемого файла iOS, а также всех изображений, звуков, видео и файлов конфигурации, необходимых для этого исполняемого файла. Пакет приложений — это то, что фактически устанавливается, когда пользователь загружает ваше приложение, поэтому, в отличие от содержимого каталогов песочницы, вы можете предполагать, что все вспомогательные ресурсы будут присутствовать независимо от устройства, на котором находится ваше приложение.

Концептуально, пакет — это просто набор файлов, но взаимодействие с ним немного отличается от использования методов файловой системы из предыдущего раздела. Вместо того, чтобы вручную генерировать пути к файлам и сохранять или загружать данные с помощью таких методов, как writeToURL: автоматически: кодировка: ошибка: вы используете класс NSBundle в качестве высокоуровневого интерфейса для медиаресурсов вашего приложения. Это делегирует некоторые мельчайшие детали за медиаресурсами базовой системе.

В дополнение к пользовательским мультимедийным ресурсам пакет приложений также содержит несколько необходимых ресурсов, таких как значок приложения, отображаемый на домашнем экране пользователя, и важные файлы конфигурации. Мы поговорим об этом в разделе «Необходимые ресурсы».

Помните, что ресурсы в комплекте приложений являются статическими, поэтому они всегда будут включены во время компиляции. Чтобы добавить медиаресурс в ваш проект, просто перетащите файл (ы) из Finder на панель Project Navigator в XCode. Мы собираемся добавить файл с именем syncfusion-logo.jpg, который вы можете найти в пакете ресурсов для этой книги, но вы можете использовать любое понравившееся изображение. В следующем разделе мы узнаем, как получить доступ к комплекту для отображения этого изображения в представлении.

tutorial_image
Рисунок 83: Добавление изображения в комплект приложения

После отпускания мыши, Xcode представит вам диалоговое окно с запросом параметров конфигурации. Флажок Копировать объекты в папку целевой группы должен быть установлен. Это говорит XCode скопировать активы в папку проекта, что обычно является желательным поведением. Опция Создать группы для любых добавленных папок использует механизм группировки XCode. Добавление к целям является наиболее важным параметром конфигурации. Он определяет, с какими целями сборки будет скомпилирован актив. Если AssetManagement не был выбран, мы бы никогда не добавили его в проект.

tutorial_image
Рисунок 84: Выбор параметров конфигурации для новых медиаресурсов

После нажатия кнопки «Готово» вы должны увидеть свой файл в Xcode Project Navigator:

tutorial_image
Рисунок 85: Медиа-актив в Навигаторе проекта

Теперь, когда у вас есть собственный ресурс в вашем комплекте приложений, вы можете получить к нему доступ через NSBundle.

Вместо того, чтобы вручную создавать пути к файлам с помощью NSURL, вы всегда должны использовать класс NSBundle в качестве программного интерфейса для вашего пакета приложений. Он обеспечивает оптимизированные функции поиска и встроенные возможности интернационализации, о которых мы поговорим в следующей главе.

Метод класса mainBundle возвращает экземпляр NSBundle, представляющий комплект вашего приложения. После этого вы можете найти ресурсы, используя метод pathForResource: ofType: instance. iOS использует специальные соглашения об именах файлов, которые позволяют NSBundle возвращать разные файлы в зависимости от того, как будет использоваться ресурс. Отделение имени файла от расширения позволяет pathForResource: ofType: выяснить, какой файл использовать автоматически, и позволяет NSBundle автоматически выбирать локализованные файлы.

Например, следующий код находит JPEG-файл с именем syncfusion-logo в комплекте приложений:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
— (void)viewDidLoad {
    [super viewDidLoad];
     
    // Find the resource.
    NSString *imagePath = [[NSBundle mainBundle]
                           pathForResource:@»syncfusion-logo»
                           ofType:@»jpg»];
    NSLog(@»Image path: %@», imagePath);
     
    // Load the resource.
    UIImage *imageData = [[UIImage alloc]
                          initWithContentsOfFile:imagePath];
    if (imageData != nil) {
        NSLog(@»Image size: %.0fx%.0f»,
              imageData.size.width, imageData.size.height);
    } else {
        NSLog(@»Could not load the file»);
    }
}

Как и текстовые файлы, поиск изображения и его загрузка — это отдельные действия. Первый вызов NSLog () должен отображать что-то вроде /path/to/sandbox/AssetManagement.app/your-image.jpg на панели вывода Xcode.

Класс UIImage представляет содержимое файла изображения и работает практически с любым типом изображения (JPEG, PNG, GIF, TIFF, BMP и некоторыми другими). Как только вы получили местоположение изображения с помощью NSBundle, вы можете передать его в initWithContentsOfFile: метод UIImage. Если файл загружен успешно, вы сможете получить доступ к размерам изображения через свойство size, которое является структурой CGSize, содержащей поля с плавающей точкой ширины и высоты.

Хотя UIImage и определяет несколько методов для рисования связанного изображения на экране (а именно drawAtPoint: и drawInRect :), его часто проще отобразить с помощью класса UIImageView. Поскольку это подкласс UIView, его можно добавить в существующую иерархию представлений, используя метод addSubview: общий для всех экземпляров представлений. UIImageView также предоставляет удобный интерфейс для управления воспроизведением анимации. Чтобы отобразить UIImage в корневом объекте представления, измените метод viewDidLoad объекта ViewController.m на следующий.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
— (void)viewDidLoad {
    [super viewDidLoad];
     
    // Find the image.
    NSString *imagePath = [[NSBundle mainBundle]
                           pathForResource:@»syncfusion-logo»
                           ofType:@»jpg»];
     
    // Load the image.
    UIImage *imageData = [[UIImage alloc]
                          initWithContentsOfFile:imagePath];
    if (imageData != nil) {
        // Display the image.
        UIImageView *imageView = [[UIImageView alloc]
                                  initWithImage:imageData];
        [[self view] addSubview:imageView];
    } else {
        NSLog(@»Could not load the file»);
    }
}

Когда вы компилируете проект, вы должны увидеть свое изображение в левом верхнем углу экрана. По умолчанию изображение не будет масштабироваться. Таким образом, если ваше изображение больше экрана, оно будет соответственно обрезано.

tutorial_image
Рисунок 86: обрезанный объект UIImageView

Чтобы изменить то, как ваш UIImageView масштабирует свое содержимое, вы должны использовать свойство contentMode UIView. Он принимает значение типа UIViewContentMode , которое является перечислением, определяющим следующие поведения.

  • UIViewContentModeScaleToFill, масштаб, чтобы заполнить размеры представления, изменяя соотношение сторон изображения при необходимости.
  • UIViewContentModeScaleAspectFit, масштабируется, чтобы соответствовать размерам представления, поддерживая соотношение сторон изображения.
  • UIViewContentModeScaleAspectFill, масштаб, чтобы заполнить размеры представления, поддерживая соотношение сторон изображения. Это может привести к обрезке части изображения.
  • UIViewContentModeCenter, используйте исходный размер изображения, но центрируйте его по горизонтали и вертикали.
  • UIViewContentModeTop, используйте размер исходного изображения, но отцентрируйте его по горизонтали и выровняйте по верху представления.
  • UIViewContentModeBottom, используйте размер исходного изображения, но отцентрируйте его по горизонтали и выровняйте по нижней части вида.
  • UIViewContentModeLeft, используйте размер исходного изображения, но отцентрируйте его вертикально и выровняйте по левому краю представления.
  • UIViewContentModeRight, используйте размер исходного изображения, но отцентрируйте его вертикально и выровняйте по правому краю просмотра.
  • UIViewContentModeTopLeft, используйте размер исходного изображения, но выровняйте его по верхнему левому углу представления.
  • UIViewContentModeTopRight, используйте размер исходного изображения, но выровняйте его по верхнему правому углу представления.
  • UIViewContentModeBottomLeft, используйте размер исходного изображения, но выровняйте его по левому нижнему углу представления.
  • UIViewContentModeBottomRight, используйте размер исходного изображения, но выровняйте его по правому нижнему углу представления.

Например, если вы хотите, чтобы ваше изображение уменьшалось до ширины экрана при сохранении его соотношения сторон, вы должны использовать UIViewContentModeScaleAspectFit для contentMode , а затем изменить ширину размеров представления изображения, чтобы она соответствовала ширине экрана ( доступно через объект [UIScreen mainScreen]). Добавьте следующее в метод viewDidLoad из предыдущего примера после [[self view] addSubview: imageView]; линия.

1
2
3
4
5
CGRect screenBounds = [[UIScreen mainScreen] bounds];
imageView.contentMode = UIViewContentModeScaleAspectFit;
CGRect frame = imageView.frame;
frame.size.width = screenBounds.size.width;
imageView.frame = frame;

Свойство frame всех экземпляров UIView определяет положение и видимую область представления (т.е. его размеры.). После изменения ширины рамки поведение UIViewContentModeScaleAspectFit автоматически рассчитало высоту рамки, в результате чего получилось следующее изображение.

tutorial_image
Рисунок 87: Уменьшение изображения до ширины экрана

Хотя в этом разделе извлечено изображение из комплекта, помните, что доступ к другим типам мультимедиа столь же прост. В предыдущем разделе мы увидели, как текстовые файлы можно загружать с помощью NSString; это работает так же с пакетами. Видео работает аналогично изображению в том, что iOS предоставляет специальный класс (MPMoviePlayerController) для включения его в существующую иерархию представлений. Аудио файлы немного отличаются, так как воспроизведение не обязательно связано с выделенным видом. Мы обсудим аудио возможности iOS позже в этой книге. А пока вернемся к комплекту приложений.

Требуемые ресурсы

В дополнение к любым пользовательским мультимедийным ресурсам, которые могут понадобиться вашему приложению, есть также три файла, которые должны быть в вашем комплекте приложений. Они описаны следующим образом.

  • Список информационных свойств , файл конфигурации, определяющий важные параметры, такие как требуемые возможности устройства, поддерживаемые ориентации и т. Д.
  • Значок приложения, значок , который отображается на домашнем экране пользователя. Это то, что пользователь нажимает, чтобы запустить ваше приложение.
  • Запустить изображение . После того, как пользователь запустит ваше приложение, это изображение, которое ненадолго появляется во время его загрузки.

Список свойств (также известный как «plist») является удобным форматом для хранения структурированных данных. Это позволяет легко сохранять массивы, словари, даты, строки и числа в постоянный файл и загружать его обратно в приложение во время выполнения. Если вы когда-либо работали с данными JSON, это та же идея.

Список свойств информации — это особый вид списка свойств, который хранится в файле Info.plist в вашем комплекте приложений. Вы можете думать об этом как о NSDictionary на основе файлов, чьи пары ключ-значение определяют параметры конфигурации для вашего приложения. Info.plist для нашего примера приложения создается из файла с именем AssetManagement-Info.plist , и вы можете редактировать его непосредственно в Xcode, выбрав его в папке «Supporting Files» в Project Navigator. Когда вы откроете его, вы должны увидеть что-то вроде следующего.

tutorial_image
Рисунок 88: Открытие файла Info.plist в Xcode

Это все параметры конфигурации, предоставляемые шаблоном. Крайний левый столбец содержит имя параметра, а самый правый — его значение. Обратите внимание, что значения могут быть логическими, числами, строками, массивами или даже целыми словарями.

По умолчанию ключи отображаются с удобочитаемыми заголовками, но это помогает — особенно при первом изучении iOS — видеть необработанные ключи, на которые ссылается официальная документация. Чтобы отобразить необработанные ключи, нажмите Ctrl + щелчок в любом месте редактора Info.plist и выберите «Показать необработанные ключи / значения». Это строки, которые нужно использовать, когда вы хотите получить доступ к параметрам конфигурации программным способом (как описано в следующем разделе).

tutorial_image
Рисунок 89: Отображение сырых ключей

В крайнем левом столбце теперь должны отображаться такие ключи, как CFBundleDevelopmentRegion, CFBundleDisplayName и т. Д. Следующие ключи необходимы для всех файлов Info.plist.

  • UIRequiredDeviceCapabilities — это массив, содержащий требования к устройству для вашего приложения. Это один из способов, которым Apple определяет, какие пользователи могут просматривать ваше приложение в App Store. Возможные значения перечислены в разделе UIRequiredDeviceCapabilities в справочнике ключей iOS.
  • UISupportedInterfaceOrientations — это массив, определяющий ориентации, поддерживаемые вашим приложением. Допустимые значения включают UIInterfaceOrientationPortrait, UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight и UIInterfaceOrientationPortraitUpsideDown.
  • CFBundleIconFile — это массив, содержащий имена файлов всех значков вашего приложения. Мы поговорим о значках приложений чуть позже.

Шаблон предоставляет значения по умолчанию для требований к устройству и поддерживаемых ориентаций, как показано на рисунке 90.

tutorial_image
Рисунок 90: Значения по умолчанию для требований к устройству и поддерживаемых ориентаций

Большинство параметров конфигурации, определенных в Info.plist, используются внутри iOS, но иногда вам может понадобиться получить к ним доступ вручную. Вы можете получить NSDictionary представления Info.plist с помощью метода infoDictionary NSBundle. Например, если вы хотите выполнить пользовательский режим запуска на основе ключа в Info.plist, вы можете выполнить быструю проверку в приложении: didFinishLaunchingWithOptions: метод AppDelegate.m, например, так:

01
02
03
04
05
06
07
08
09
10
— (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSDictionary* infoDict = [[NSBundle mainBundle] infoDictionary];
    NSArray *supportedOrientations = [infoDict objectForKey:@»UISupportedInterfaceOrientations»];
    if ([supportedOrientations containsObject:@»UIInterfaceOrientationPortraitUpsideDown»]) {
        NSLog(@»Do something special to enable an upside-down app»);
    } else {
        NSLog(@»Can assume the app won’t display upside-down»);
    }
    return YES;
}

В комплект вашего приложения должен входить хотя бы один значок для отображения на главном экране, но также можно указать несколько значков для разных ситуаций. Например, вы можете использовать другой дизайн для меньшего значка, который появляется в результатах поиска, или использовать изображение с высоким разрешением для устройств с дисплеями Retina. Xcode позаботится обо всем этом для вас.

Ключ CFBundleIconFiles в Info.plist должен быть массивом, содержащим имена файлов всех значков вашего приложения. За исключением значка App Store, вы можете использовать любое имя для файлов. Обратите внимание, что вам не нужно указывать предполагаемое использование каждого файла — iOS автоматически выберет соответствующий значок в зависимости от размеров.

tutorial_image
Рисунок 91: Пользовательские значки приложений iPhone с версиями высокого разрешения для дисплеев Retina

Если ваше приложение поддерживает устройства с дисплеями Retina, вы должны также включить версию каждого значка в высоком разрешении и дать ему то же имя файла с добавленным @ 2x. Например, если ваш основной файл значков назывался app-icon.png, версия дисплея Retina должна называться app-icon@2x.png.

В следующей таблице перечислены стандартные значки приложений iOS, но обязательно ознакомьтесь с Руководством по интерфейсу пользователя iOS для более подробного обсуждения. Этот документ также содержит подробные рекомендации по созданию графических значков. Все иконки должны использовать формат PNG.

Тип значка Платформа необходимые Стандартный размер Размер сетчатки Описание/
Значок App Store iPhone и iPad да 512 × 512 1024 × 1024 Изображение представлено покупателям в iTunes. Этот файл должен называться iTunesArtwork или iTunesArtwork @ 2x (без расширения).
Главный значок iPhone да 57 × 57 114 × 114 Значок, который появляется на главном экране iPhone.
Главный значок IPad да 72 × 72 144 × 144 Значок, который появляется на главном экране iPad.
Маленькая иконка iPhone нет 29 × 29 58 × 58 Значок отображается рядом с результатами поиска и в приложении «Настройки» для iPhone.
Маленькая иконка IPad нет 50 × 50 100 × 100 Значок отображается рядом с результатами поиска и в приложении «Настройки» для iPad.

Далее вы добавите значок в пример приложения. В пакете ресурсов для этой книги вы найдете четыре примера иконок: app-icon.png, app-icon@2x.png, app-icon-small.png и app-icon-small@2x.png. Перетащите все это в Project Navigator, чтобы добавить их в комплект приложений, а затем откройте AssetManagement-Info.plist и убедитесь, что вы просматриваете необработанные ключи или значения. Добавьте новую строку и введите CFBundleIconFiles для ключа (не путать с CFBundleIcons или CFBundleIconFile ). Это автоматически добавит пустой элемент в массив, который вы можете просмотреть, щелкнув треугольник рядом с элементом CFBundleIconFiles . Добавьте все четыре файла значков в массив, чтобы он выглядел следующим образом. Порядок не имеет значения.

tutorial_image
Рисунок 92: Добавление файлов значков в Info.plist

Теперь, когда вы запускаете свой проект, вы должны увидеть значок собственного приложения на главном экране. Возможно, вам придется перезапустить iOS Simulator, чтобы это работало.

tutorial_image
Рисунок 93: Значок пользовательского приложения на главном экране

Попробуйте перетащить домашний экран вправо несколько раз, пока не дойдете до экрана поиска. Если вы начнете вводить «управление активами», вы увидите маленькую версию значка в результатах поиска, как показано на рисунке 94:

tutorial_image
Рисунок 94: Небольшой значок приложения, используемый в результатах поиска

И это все, что нужно для настройки иконок для вашего приложения iPhone.

Последний требуемый медиа-актив для любого приложения iOS — это изображение запуска. Изображение запуска отображается сразу же, когда пользователь открывает ваше приложение. Идея состоит в том, чтобы создать у пользователя впечатление, что ваше приложение запущено немедленно, хотя загрузка может занять несколько секунд. Apple не рекомендует разработчикам использовать изображения запуска в качестве страницы с информацией о программе или заставки. Вместо этого он должен быть скелетом начального экрана вашего приложения.

Например, рассмотрим приложение master-detail, которое мы создали в предыдущей главе. Идеальный стартовый образ — это просто пустой главный список:

tutorial_image
Рисунок 95: Соответствующее изображение запуска для приложения master-detail

Как вы можете видеть из предыдущих глав, изображение запуска — это, по сути, скриншот начального экрана вашего приложения, без каких-либо динамических данных. Это позволяет избежать резких изменений в пользовательском интерфейсе. Опять же, идея состоит в том, чтобы преуменьшить важность запуска приложения, сделав переход максимально плавным: от выбора приложения к изображению запуска на начальном экране. IOS Simulator имеет удобный инструмент захвата экрана для создания стартовых изображений. Как только ваше приложение будет готово, запустите его в симуляторе и перейдите в Edit> Copy Screen.

Как и значки приложений, можно иметь несколько изображений запуска в зависимости от устройства или разрешения экрана. Для изображений запуска используется тот же аффикс @ 2x для изображений с высоким разрешением, но также возможно нацеливание на определенные устройства, добавив модификатор использования сразу после базового имени. Например, iPhone 5 имеет размеры экрана, отличные от предыдущих поколений, и, следовательно, требует своего собственного образа запуска. Чтобы указать iOS использовать определенный файл для устройств iPhone 5, вы должны добавить -568h к его базовому имени, что даст вам что-то вроде launch-image-568h@2x.png (обратите внимание, что iPhone 5 имеет дисплей Retina, поэтому связанный запуск изображение всегда будет иметь @ 2x в имени файла).

В следующей таблице перечислены требования к размерам для изображений запуска iOS.

Платформа Стандартный размер Размер сетчатки
iPhone (до 4-го поколения) 320 × 480 640 × 960 iPhone (5-го поколения) 640 × 1136 640 × 1136 IPad 768 × 1004 1536 × 2008

Если у вас есть образ запуска, его добавление в приложение очень похоже на настройку значков приложения. Сначала добавьте файлы на верхний уровень вашего пакета приложений, а затем добавьте базовое имя в ключ UILaunchImageFile вашего Info.plist. Например, если ваши образы запуска назывались launch-image.png, launch-image@2x.png и launch-image-568h@2x.png, вы должны использовать launch-image в качестве значения для UILaunchImageFile.

Если вы не укажете UILaunchImageFile, iOS будет использовать файлы Default.png, Default@2x.png и Default-568h@2x.png. Эти образы запуска по умолчанию предоставляются шаблонами XCode.


В этой главе рассказывалось о многих встроенных инструментах управления активами в iOS. Мы поговорили о файловой системе песочницы приложения и о том, как читать и записывать динамические файлы из различных предопределенных каталогов. Мы также рассмотрели пакет приложений, который содержит все ресурсы, которые будут распространяться вместе с приложением. В дополнение к любым пользовательским мультимедийным ресурсам пакет приложений должен включать в себя список информационных свойств, значки приложений и образы запуска.

Пакеты — это удобный способ распространения приложения, но они также предоставляют встроенные возможности интернационализации. В следующей главе мы научимся показывать разные файлы разным пользователям в зависимости от языковых настроек. И, благодаря NSBundle, для этого потребуется совсем немного дополнительного кода.

Этот урок представляет собой главу из iOS, сжатой , бесплатной электронной книги от команды Syncfusion .