Вандад Нахавандипур - iOS. Приемы программирования
controller.mediaTypes = [[NSArray alloc]
initWithObjects: requiredMediaType, nil];
controller.allowsEditing = YES;
controller.delegate = self;
[self.navigationController presentModalViewController: controller
animated: YES];
} else {
NSLog(@"Camera is not available.");
}
}
Методы isCameraAvailable и doesCameraSupportTakingPhotos, использованные в данном примере, подробно рассмотрены в разделе 13.1.
Обсуждение
Обычно после того, как пользователь успешно снимет фотографию на устройство с iOS, он ожидает, что этот снимок сохранится в его библиотеке фотографий. Однако приложения, не входящие в стандартный комплект программ iOS, могут запросить пользователя сделать снимок с помощью класса UIImagePickerController, а потом обработать это изображение. В таком случае пользователь поймет, что предоставленное нами приложение может и не сохранять сделанный снимок в библиотеке фотографий, а вместо этого использовать фотографию внутрисистемно. Например, если программа для обмена мгновенными сообщениями позволяет пользователю передавать фотографии на другие устройства, то пользователь поймет, что сделанный им снимок не будет сохранен в библиотеке фотографий, а, напротив, будет передан по Интернету другому пользователю.
Но если вы решите, что хотите сохранить экземпляр UIImage в библиотеке фотографий на пользовательском устройстве, то можете применить функцию UIImageWriteToSavedPhotosAlbum. Она принимает четыре параметра:
• изображение;
• объект, который станет получать уведомления всякий раз, когда изображение будет полностью сохранено;
• параметр, указывающий селектор (этот селектор будет вызываться применительно к целевому объекту). Данный параметр идет вторым, а селектор вызывается по завершении операции;
• значение контекста, передаваемое указанному селектору, как только операция будет завершена.
Второй, третий и четвертый параметры для этой процедуры указывать не обязательно. Если вы зададите и второй, и третий параметры, то четвертый параметр все равно останется опциональным. Вот, например, селектор, который я выбрал для нашего примера:
— (void) imageWasSavedSuccessfully:(UIImage *)paramImage
didFinishSavingWithError:(NSError *)paramError
contextInfo:(void *)paramContextInfo{
if (paramError == nil){
NSLog(@"Image was saved successfully.");
} else {
NSLog(@"An error happened while saving the image.");
NSLog(@"Error = %@", paramError);
}
}
Если вы попытаетесь воспользоваться процедурой UIImageWriteToSavedPhotosAlbum для сохранения фотоснимка в пользовательской библиотеке фотографий и приложение впервые выполняет эту операцию на данном устройстве, то iOS запросит у пользователя разрешение на такую операцию (рис. 13.1). Таким образом, пользователь может позволить или не позволить приложению сохранять фотографии на устройстве. В конце концов, это пользовательское устройство и мы не можем делать на этом устройстве ничего такого, чего нам не разрешил пользователь. Если пользователь дает разрешение, то процедура UIImageWriteToSavedPhotosAlbum продолжит сохранение изображения. Если разрешение не получено, то селектор обработчика завершения по-прежнему будет вызываться, но параметр didFinishSavingWithError этого селектора будет устанавливаться в валидный экземпляр ошибки.
Рис. 13.1. iOS запрашивает у пользователя права доступа, прежде чем программа сможет сохранить снимок в библиотеке фотографий
Теперь, если пользователь отказывает приложению в праве доступа, все последующие вызовы процедуры UIImageWriteToSavedPhotosAlbum будут неуспешными, пока пользователь вручную не изменит настройки своего устройства (рис. 13.2).
Рис. 13.2. Приложению не разрешен доступ к пользовательской библиотеке фотографий
Если в данном селекторе вы получаете параметр error, значение которого равно nil, это означает, что изображение было успешно сохранено в пользовательской библиотеке фотографий. В противном случае можно получить значение данного параметра, чтобы выяснить, в чем заключается ошибка.
13.5. Сохранение видео в библиотеке фотографий
Постановка задачи
Требуется сохранить в библиотеке фотографий видеоролик, доступный по URL, например ролик из пакета вашего приложения.
Решение
Воспользуйтесь методом экземпляра writeVideoAtPathToSavedPhotosAlbum: completionBlock:, относящимся к классу ALAssetsLibrary:
#import «AppDelegate.h»
#import <AssetsLibrary/AssetsLibrary.h>
@interface AppDelegate ()
@property (nonatomic, strong) ALAssetsLibrary *assetsLibrary;
@end
@implementation AppDelegate
— (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.assetsLibrary = [[ALAssetsLibrary alloc] init];
NSURL *videoURL = [[NSBundle mainBundle] URLForResource:@"MyVideo"
withExtension:@"MOV"];
if (videoURL!= nil){
[self.assetsLibrary
writeVideoAtPathToSavedPhotosAlbum: videoURL
completionBlock: ^(NSURL *assetURL, NSError *error) {
if (error == nil){
NSLog(@"no errors happened");
} else {
NSLog(@"Error happened while saving the video.");
NSLog(@"The error is = %@", error);
}
}];
} else {
NSLog(@"Could not find the video in the app bundle.");
}
return YES;
}
Обсуждение
Фреймворк Assets Library — удобный посредник между разработчиком и библиотекой фотографий. Как будет указано в разделе 13.6, в iOS SDK вам предоставляются встроенные компоненты графического пользовательского интерфейса, которыми можно пользоваться для доступа к содержимому библиотеки фотографий. Тем не менее иногда может потребоваться и непосредственный доступ к этому содержимому. В таких случаях следует пользоваться фреймворком библиотеки ресурсов (Assets Library).
Выделив и инициализировав объект Assets Library типа ALAssetsLibrary, можно пользоваться методом экземпляра writeVideoAtPathToSavedPhotosAlbum: completionBlock:, относящимся к данному объекту, для записи видео с URL в библиотеку фотографий. Все, что от вас требуется, — предоставить URL видеоролика в форме NSURL, а также блоковый объект, чей код будет вызываться после сохранения видео. Этот блоковый объект должен принимать два параметра типов NSURL и NSError.
Если параметр error имеет значение nil, процесс сохранения прошел нормально и поводов для беспокойства нет. Одна из типичных ошибок, которую iOS может вам вернуть в такой ситуации, примерно такова:
Error Domain=ALAssetsLibraryErrorDomain Code=-3302 «Invalid data»
UserInfo=0x79 23590 {NSLocalizedFailureReason=
There was a problem writing this asset because
the data is invalid and cannot be viewed or played.,
NSLocalizedRecoverySuggestion=Try with different data,
NSLocalizedDescription=Invalid data}
Такое сообщение об ошибке вы можете получить и в случае, если попытаетесь передать URL (уникальный идентификатор ресурса), не относящийся к пакету вашего приложения.
Первый параметр, передаваемый блоковому объекту, который, в свою очередь, предоставляется методу writeVideoAtPathToSavedPhotosAlbum: completionBlock:, будет указывать URL видео, сохраненного в библиотеке ресурсов. URL такого рода может иметь следующий вид:
assets-library://asset/asset.MOV?id=F9B5F733-487C-
4418-8C8D-46ABC9FEE23B&ext=MOV
Если ваша программа впервые пытается обратиться к библиотеке фотографий на пользовательском устройстве, то iOS спросит у пользователя, разрешена такая операция или нет. Если пользователь даст разрешение, то вызов метода writeVideoAtPathToSavedPhotosAlbum: completionBlock: будет успешным. Если же разрешение получено не будет, то объект ошибки внутри блока завершения будет валидным объектом ошибки, который вы можете проверить и над которым можете выполнять действия. Если ранее пользователь не разрешил вашему приложению доступ к библиотеке фотографий, то вы не сможете изменить это решение программно. Лишь когда сам пользователь решит предоставить вам доступ к библиотеке фотографий, он изменит соответствующие настройки в разделах Settings (Настройки) и Privacy (Конфиденциальность).
В разделе 13.7 будет рассказано, как использовать такой URL при загрузке в память данных для видеофайла.
13.6. Получение фото и видео из библиотеки фотографий
Постановка задачи
Необходимо предоставить пользователю возможность выбирать фото или видео из своей библиотеки фотографий и использовать их в приложении.
Решение
При работе с объектом UIImagePickerController используйте UIImagePickerControllerSourceTypePhotoLibrary в качестве типа источника и значение kUTTypeImage или kUTTypeMovie для типа медийной информации: