等待Xcode方法完成

时间:2015-04-12 20:06:21

标签: ios avasset completionhandler

我正在使用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;
    }
]};

我该怎么分配给它?

2 个答案:

答案 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);
     }
 }];
相关问题