我正在使用generateCGImagesAsynchronouslyForTimes制作一些图片并将它们保存到NSMutableArray
,现在当函数generateCGImagesAsynchronouslyForTimes
完成时我想要使用这个数组中的图像,我怎么能得到我想要的代码在生成完所有图像后执行exectue。我只是把它放在completionHandler
代码块中,但我不希望它运行多次我只想运行一次,在这个方法完成之后。
修改
这都在- (BFTask *)createImage:(NSInteger)someParameter {
AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:passsedAsset];
[imageGenerator generateCGImagesAsynchronouslyForTimes:times
completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime,
AVAssetImageGeneratorResult result, NSError *error) {
if (result == AVAssetImageGeneratorSucceeded) {
UIImage *img = [UIImage imageWithCGImage:image];
NSData *imgData = UIImageJPEGRepresentation(img, 1.0);
UIImage *saveImage = [[UIImage alloc] initWithData:imgData];
[mutaleArray addObject:saveImage];
//I get Assigment to read only property error on line below
completionSource.task = saveImage;
}
]};
我该怎么分配给它?
答案 0 :(得分:3)
我首先考虑的两种方法是NSOperationQueue(您可以检测它何时为空)或者更容易选择使用Bolts框架。
Bolts允许你创建一个异步运行的任务数组,然后一旦完成它继续下一个位。
让我联系一下......
你去...... https://github.com/BoltsFramework
你也可以通过cocoapods来实现这一目标,这使得一切变得更加容易。
螺栓如何工作的一个例子......
目前,您将拥有一个异步创建图像的功能。像... - (UIImage *)createImage: (id)someParameter;
现在你可以做到这一点......
- (BFTask *)createImage:(NSInteger)someParameter
{
BFTaskCompletionSource *completionSource = [BFTaskCompletionSource taskCompletionSource];
//create your image asynchronously and then set the result of the task
someAsyncMethodToCreateYourImageWithACompletionBlock...^(UIImage *createdImage){
// add the images here...
[self.imageArray addObject:createdImage];
// the result doesn't need to be the image it just informs
// that this one task is complete.
completionSource.result = createdImage;
}
return completionSource.task;
}
现在你必须并行运行任务......
- (void)createAllTheImagesAsyncAndThenDoSomething
{
// create the empty image array here
self.imageArray = [NSMutableArray array];
NSMutableArray *tasks = [NSMutableArray array];
for (NSInteger i=0 ; i<100 ; ++i) {
// Start this creation immediately and add its task to the list.
[tasks addObject:[self createImage:i]];
}
// Return a new task that will be marked as completed when all of the created images are finished.
[[BFTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(BFTask *task){
// this code will only run once all the images are created.
// in here self.imageArray is populated with all the images.
}
}
答案 1 :(得分:2)
假设generateCGImagesAsynchronouslyForTimes:completionHandler:
按顺序调用其完成处理程序(这似乎合理,但文档没有明确承诺),那么这很简单。只需将__block
变量设置为times
的计数,并在每次完成时减少一次。当它为零时,请调用其他函数。
__block NSInteger count = [times count];
[imageGenerator generateCGImagesAsynchronouslyForTimes:times
completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime,
AVAssetImageGeneratorResult result, NSError *error) {
... Do all the stuff ...
if (--count <= 0) {
finalize()
}
如果generateCGImagesAsynchronouslyForTimes:
实际上并行工作,因此可以并行调用完成处理程序,那么您可以使用调度组处理所有这些。
dispatch_group_t group = dispatch_group_create();
//
// Enter the group once for each time
//
[times enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
dispatch_group_enter(group);
}];
//
// This local variable will be captured, so you don't need a property for it.
//
NSMutableArray *results = [NSMutableArray new];
//
// Register a block to fire when it's all done
//
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"Whatever you want to do when everything is done.");
NSLog(@"results is captured by this: %@", results);
});
AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:nil];
[imageGenerator generateCGImagesAsynchronouslyForTimes:times
completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime,
AVAssetImageGeneratorResult result, NSError *error)
{
if (result == AVAssetImageGeneratorSucceeded) {
//
// Create saveImage
//
id saveImage = @"";
//
// Update external things on a serial queue.
// You may use your own serial queue if you like.
//
dispatch_sync(dispatch_get_main_queue(), ^{
[results addObject:saveImage];
});
//
// Signal we're done
//
dispatch_group_leave(group);
}
}];