2015-04-12 3 views
1

J'utilise generateCGImagesAsynchronouslyForTimes pour faire quelques images et les enregistrer dans un NSMutableArray, maintenant que la fonction generateCGImagesAsynchronouslyForTimes se termine, je veux utiliser l'image dans ce tableau, comment puis-je avoir le code que je veux produire après toutes les images ont été générées pour finir. Je voudrais juste le mettre dans le bloc de code completionHandler, mais je ne veux pas l'exécuter plusieurs fois, je veux juste l'exécuter une fois, après que cette méthode est terminée.Attendre la fin de la méthode Xcode

EDIT

C'est tout à l'intérieur - (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; 
    } 
]}; 

Que dois-je en lui assignant à?

Répondre

3

Les deux approches que je considérerais en premier sont NSOperationQueue (vous pouvez détecter quand il est vide) ou le choix le plus facile d'utiliser le framework Bolts.

Les boulons vous permettent de créer un tableau de tâches qui s'exécutent de manière asynchrone, puis une fois terminé, il passe au bit suivant.

Laissez-moi un lien ...

vous allez ici ... https://github.com/BoltsFramework

Vous pouvez également obtenir ce à travers cocoapods ce qui rend tout beaucoup plus facile.

Un exemple de boulons fonctionne ...

Au moment où vous aurez une fonction qui crée une image de manière asynchrone. Quelque chose comme ... - (UIImage *)createImage: (id)someParameter; bien vous pouvez maintenant le faire ...

- (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; 
} 

Maintenant, vous devez exécuter les tâches en parallèle ...

- (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. 
    } 
} 
+0

Merci pour le post, je ne vote BTW vers le bas, mais pourriez-vous donner des précisions sur la façon d'utiliser des boulons – iqueqiorio

+0

Vérifiez le lien GitHub. Je suis sur mon téléphone, donc je ne peux pas faire du code très bien. La section dans le read me s'appelle "Tasks in Parallel". Il vous montrera comment créer un tableau de tâches et ensuite avoir un seul gestionnaire d'achèvement une fois que le tableau entier aura fini le traitement. – Fogmeister

+0

Pourriez l'électeur vers le bas s'il vous plaît laisser un commentaire pour expliquer pourquoi ma réponse est incorrecte? Ou sont-ils simplement lâches? – Fogmeister

2

En supposant que generateCGImagesAsynchronouslyForTimes:completionHandler: appelle ses gestionnaires d'achèvement séquentielle (cela semble raisonnable, mais les docs ne le promettent pas explicitement), alors c'est très simple. Il suffit de définir une variable __block sur le nombre de vos times et de la décrémenter une fois par achèvement. Quand c'est zéro, appelez votre autre fonction.

__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() 
     } 

Si generateCGImagesAsynchronouslyForTimes: en réalité pour le travail en parallèle et donc pourrait appeler les gestionnaires d'achèvement en parallèle, vous pouvez gérer tout cela avec des groupes d'expédition.

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); 
    } 
}];