我想从视频中获取一系列图片。它运行良好,但我怀疑在哪个线程中调用完成处理程序。
我在新操作中调用了此方法(generateCGImagesAsynchronouslyForTimes:
),并在完成处理程序中更新了UI。用户界面得到更新。
但通常在辅助线程中不会发生UI更新?我的疑问是在当前调用线程或主线程中调用的完成处理程序?
我的代码是:
__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];
}
}
};
答案 0 :(得分:4)
文件清楚地说明了这一点:
与AV Foundation同步编程
来自AV Foundation的调用 - 块,键值观察器和通知处理程序的调用 - 不保证在任何特定线程或队列上进行。相反,AV Foundation会在执行其内部任务的线程或队列上调用这些处理程序。您负责测试调用处理程序的线程或队列是否适合您要执行的任务。如果不是(例如,如果要更新用户界面并且标注不在主线程上),则必须将任务的执行重定向到您识别的安全线程或队列,或者您为其创建的队列。目的
另请参阅:AV Foundation Programming Guide
修改强>
问题是,您不保留/释放参数 im 中提供的CGImageRef
图像,因为您稍后在NSBlockOperation中使用它。在调用块之前,需要将保留在块之外(来自NSBlockOperation),并在块返回之前(在块内)释放它。
答案 1 :(得分:2)
一般来说,回调必须返回主线程,因为如果它不是主线程,则无法保证它的运行循环运行的线程。
除非你正在安排你正在创建与其他操作(依赖项)相关的块,否则我不确定该块给你带来了什么好处,因为图像加载是异步的,所以你可以从主线程触发它而不用阻止任何事情。
根据您的评论,在这种情况下,您应该切换代码。在完成块内创建块操作,为您提供图像。将每个块操作添加到队列中。块操作只需获取图像并将其保存到磁盘。