Вызывается обработчик завершения AVAssetImageGenerator в основном потоке?
Я пытаюсь получить массив изображений из видео. Это работает хорошо, но я сомневаюсь, что в каком потоке вызывается обработчик завершения.
Я назвал этот метод (
generateCGImagesAsynchronouslyForTimes:
) в новой операции, и я обновил интерфейс в обработчике завершения. Пользовательский интерфейс обновляется.Но обычно обновление пользовательского интерфейса не происходит во вторичном потоке? Я сомневаюсь, что обработчик завершения вызывается в текущем вызывающем потоке или основном потоке?
Мой код:
__block unsigned int i = 0;
AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, CGImageRef im, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error){
i++;
if(result == AVAssetImageGeneratorSucceeded){
//Create a block to save the image in disk
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *documentsDirectory = [NSHomeDirectory()
stringByAppendingPathComponent:@"Documents"];
NSError *error = nil;
//Create file path for storing the image
NSString *videoOutputPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"VideoFrames%i.png", i]];
//Delete if already any image exist
if ([fileMgr fileExistsAtPath:videoOutputPath]){
if ([fileMgr removeItemAtPath:videoOutputPath error:&error] != YES)
NSLog(@"Unable to delete file: %@", [error localizedDescription]);
}
//Convert the CGImageRef to UIImage
UIImage *image = [UIImage imageWithCGImage:im];//**This line gives error: EXE_BAD_ACCESS**
//Save the image
if(![UIImagePNGRepresentation(image) writeToFile:videoOutputPath options:NSDataWritingFileProtectionNone error:&error])
NSLog(@"Failed to save image at path %@", videoOutputPath);
}];
//Add the operation to the queue
[self.imageWritingQueue addOperation:operation];
}
}
};
2 ответа
IIRC, да. Но вы можете проверить это, и для безопасности вы можете обернуть ваш код в блок, который отправляет его в основной поток.
Вообще говоря, обратный вызов должен возвращаться к основному потоку, поскольку нельзя гарантировать, что поток, из которого он запущен, выполняет цикл выполнения, если он не является основным потоком.
Если вы не планируете блок, который вы создаете, относительно других операций (зависимостей), тогда я не уверен, какое преимущество дает блок, поскольку загрузка изображения асинхронна, поэтому вы можете запускать его из основного потока, не блокируя ничего.
Из вашего комментария, в этом случае вы должны поменять код. Создайте блок операции внутри блока завершения, который предоставляет вам изображение. Добавьте каждую операцию блока в свою очередь. Операция блока просто берет изображение и сохраняет его на диск.
В документации четко сказано:
Параллельное программирование с AV Foundation
Вызовы из AV Foundation - вызовы блоков, наблюдателей значения ключа и обработчиков уведомлений - не гарантированно выполняются в каком-либо конкретном потоке или очереди. Вместо этого AV Foundation вызывает эти обработчики в потоках или очередях, в которых он выполняет свои внутренние задачи. Вы несете ответственность за проверку соответствия потока или очереди, в которой вызывается обработчик, задачам, которые вы хотите выполнить. Если это не так (например, если вы хотите обновить пользовательский интерфейс, а выноска отсутствует в главном потоке), вы должны перенаправить выполнение ваших задач в безопасный поток или очередь, которые вы распознаете, или которые вы создаете для цель.
Смотрите также: Руководство по программированию AV Foundation
Редактировать:
Проблема в том, что вы не сохраняете / не освобождаете CGImageRef
изображение предоставлено в параметре im, так как вы используете его в NSBlockOperation позже. Вам нужно сохранить его за пределами блока (из NSBlockOperation), прежде чем вызывать блок, и освободить его до того, как блок вернется (внутри блока).