Вандад Нахавандипур - iOS. Приемы программирования
Обсуждение
Класс UIVideoEditorController, содержащийся в iOS SDK, позволяет программисту вывести на экран перед пользователем специальный интерфейс для редактирования. Все, что требуется сделать, — предоставить URL видеоролика, который предполагается отредактировать, а потом отобразить в модальном виде контроллер для редактирования видео. Не допускайте наложения вида этого контроллера на любые другие виды и не изменяйте этот вид.
При вызове метода presentModalViewController: animated: сразу же после метода dismissModalViewControllerAnimated: контроллера вида приложение завершится с ошибкой времени исполнения. Необходимо дождаться, пока первый контроллер вида не будет убран с экрана, и только потом отображать второй контроллер вида. Можно пользоваться относящимся к контроллерам вида методом viewDidAppear:, помогающим определить, когда отобразится ваш вид. На данном этапе можно быть уверенным, что все модальные контроллеры видов уже убраны.
Итак, продолжим и объявим контроллер вида со всеми необходимыми свойствами:
#import «ViewController.h»
#import <MobileCoreServices/MobileCoreServices.h>
#import <AssetsLibrary/AssetsLibrary.h>
@interface ViewController ()
<UINavigationControllerDelegate,
UIVideoEditorControllerDelegate,
UIImagePickerControllerDelegate>
@property (nonatomic, strong) NSURL *videoURLToEdit;
@property (nonatomic, strong) ALAssetsLibrary *assetsLibrary;
@end
@implementation ViewController
<# Остаток вашего кода находится здесь #>
Далее нужно обработать различные сообщения, получаемые от делегата видеоредактора в контроллере вида:
— (void)videoEditorController:(UIVideoEditorController *)editor
didSaveEditedVideoToPath:(NSString *)editedVideoPath{
NSLog(@"The video editor finished saving video");
NSLog(@"The edited video path is at = %@", editedVideoPath);
[editor dismissModalViewControllerAnimated: YES];
}
— (void)videoEditorController:(UIVideoEditorController *)editor
didFailWithError:(NSError *)error{
NSLog(@"Video editor error occurred = %@", error);
[editor dismissModalViewControllerAnimated: YES];
}
— (void)videoEditorControllerDidCancel:(UIVideoEditorController *)editor{
NSLog(@"The video editor was cancelled");
[editor dismissModalViewControllerAnimated: YES];
}
Когда вид загрузится, мы должны будем отобразить для пользователя вид для выбора видео. Видео он может выбрать из библиотеки, а потом мы предоставим возможность его обрабатывать:
— (BOOL) cameraSupportsMedia:(NSString *)paramMediaType
sourceType:(UIImagePickerControllerSourceType)paramSourceType{
__block BOOL result = NO;
if ([paramMediaType length] == 0){
NSLog(@"Media type is empty.");
return NO;
}
NSArray *availableMediaTypes =
[UIImagePickerController
availableMediaTypesForSourceType: paramSourceType];
[availableMediaTypes enumerateObjectsUsingBlock:
^(id obj, NSUInteger idx, BOOL *stop) {
NSString *mediaType = (NSString *)obj;
if ([mediaType isEqualToString: paramMediaType]){
result = YES;
*stop= YES;
}
}];
return result;
}
— (BOOL) canUserPickVideosFromPhotoLibrary{
return [self cameraSupportsMedia:(__bridge NSString *)kUTTypeMovie
sourceType: UIImagePickerControllerSourceTypePhotoLibrary];
}
— (BOOL) isPhotoLibraryAvailable{
return [UIImagePickerController
isSourceTypeAvailable:
UIImagePickerControllerSourceTypePhotoLibrary];
}
— (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear: animated];
static BOOL beenHereBefore = NO;
if (beenHereBefore){
/* Отображаем элемент для выбора даты только после того, как вызывается
метод viewDidAppear:, что происходит при каждом отображении вида
нашего контроллера вида */
return;
} else {
beenHereBefore = YES;
self.assetsLibrary = [[ALAssetsLibrary alloc] init];
}
if ([self isPhotoLibraryAvailable] &&
[self canUserPickVideosFromPhotoLibrary]){
UIImagePickerController *imagePicker =
[[UIImagePickerController alloc] init];
/* Задаем тип источника для библиотеки фотографий. */
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
/* Требуется, чтобы пользователь мог выбирать видеоролики
из библиотеки. */
NSArray *mediaTypes = [[NSArray alloc] initWithObjects:
(__bridge NSString *)kUTTypeMovie, nil];
imagePicker.mediaTypes = mediaTypes;
/* Задаем делегат для текущего контроллера вида. */
imagePicker.delegate = self;
/* Отображаем окно для выбора изображений. */
[self.navigationController presentModalViewController: imagePicker
animated: YES];
}
}
Далее нам необходимо узнать, когда пользователь сделает выбор (то есть выберет видеоролик). Обработаем различные сообщения делегата, обслуживающего инструмент для выбора изображений:
— (void) imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info{
NSLog(@"Picker returned successfully.");
NSString *mediaType = [info objectForKey:
UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]){
self.videoURLToEdit =
[info objectForKey: UIImagePickerControllerMediaURL];
}
[picker dismissModalViewControllerAnimated: YES];
/* Сначала убедимся, что редактор видео способен обрабатывать видео,
путь к которому в папке документов мы указали. */
if ([UIVideoEditorController canEditVideoAtPath: videoPath]){
/* Инстанцируем редактор видео. */
UIVideoEditorController *videoEditor =
[[UIVideoEditorController alloc] init];
/* Становимся делегатом видеоредактора. */
videoEditor.delegate = self;
/* Убеждаемся, что задали путь к видеоролику. */
videoEditor.videoPath = videoPath;
/* А теперь отображаем видеоредактор. */
[self.navigationController presentModalViewController: videoEditor
animated: YES];
self.videoURLToEdit = nil;
} else {
NSLog(@"Cannot edit the video at this path");
}
}
}];
}
— (void) imagePickerControllerDidCancel:(UIImagePickerController *)picker{
NSLog(@"Picker was cancelled");
self.videoURLToEdit = nil;
[picker dismissViewControllerAnimated: YES completion: nil];
}
В данном примере пользователь может выбрать любое видео из библиотеки фотографий. Как только он это сделает, мы отобразим контроллер видеоредактора, указав путь к видеоролику. Этот путь передает нам инструмент для выбора видео в методе делегата.
Делегат контроллера видеоредактора получает важные сообщения о состоянии этого видеоредактора. Объект делегата должен соответствовать протоколам UIVideoEditorControllerDelegate и UINavigationControllerDelegate. В данном примере мы решили, что делегатом видеоредактора должен стать контроллер вида. Как только редактирование будет закончено, объект делегата получит от контроллера видеоредактора метод делегата videoEditorController: didSaveEditedVideoToPath:. Путь к отредактированному видео будет передан в параметре didSaveEditedVideoToPath.
Прежде чем попытаться отобразить для пользователя интерфейс видеоредактора, нужно вызывать метод класса canEditVideoAtPath:, относящийся к классу UIVideoEditorController. Мы это делаем, чтобы убедиться, что тот путь, который вы пытаетесь редактировать, доступен для обработки в контроллере. Если возвращаемое значение этого метода класса равно YES, можно переходить к конфигурированию и отображению интерфейса редактора видео. Если нет — идем другим путем. Возможно, потребуется отобразить для пользователя предупреждение.
См. также
Разделы 13.6 и 13.7.
Глава 14. Многозадачность
14.0. Введение
Многозадачность — это способ работы, обеспечивающий фоновое выполнение. Иначе говоря, приложение может работать как обычно — выполнять задачи, порождать новые потоки, слушать уведомления, реагировать на события, — но просто ничего не отображать на экране и не взаимодействовать с пользователем каким-либо образом. Когда пользователь нажимает на устройстве кнопку Home (Домой) — в более ранних версиях iPhone и iPad эта кнопка завершала работу приложения, — программа просто переходит в фоновый режим.
Когда ваше приложение переходит в фоновый режим (например, при нажатии кнопки Home (Домой)), а затем возвращается на передний план (когда пользователь вновь выбирает это приложение), система начинает посылать различные сообщения. Ожидается, что эти сообщения будут получены объектом, который мы назначаем делегатом нашего приложения. Например, когда приложение переходит в фоновый режим, делегат приложения получит метод applicationDidEnterBackground:. Аналогично, когда пользователь вновь вернет приложение в приоритетный режим, то есть возобновит с ним работу, делегат приложения получит делегатное сообщение applicationWillEnterForeground:.