1

我正在使用 generateCGImagesAsynchronouslyForTimes 制作一些图像并将它们保存到 a NSMutableArray,现在当函数generateCGImagesAsynchronouslyForTimes完成时我想使用这个数组中的图像,在所有图像都生成完成后,我怎样才能拥有我想要执行的代码。我只想把它放在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;
    }
]};

我应该把它分配给什么?

4

2 回答 2

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.
    }
}
于 2015-04-12T20:09:59.790 回答
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);
     }
 }];
于 2015-04-13T00:36:20.543 回答