2011-08-29 3 views
24

Je voudrais attendre que ce code soit exécuté avant de continuer mais comme ces blocs sont appelés de façon assynchrone je ne sais pas comment faire ???Attendez que les blocs assetForURL soient complétés

NSURL *asseturl; 
NSMutableArray *tmpListAsset = [[NSMutableArray alloc] init]; 

ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init] autorelease]; 
NSMutableArray *objectsToRemove = [[NSMutableArray alloc] init]; 
for (NSDictionary *dico in assetsList) { 
    asseturl = [NSURL URLWithString:[dico objectForKey:@"assetUrl"]]; 
    NSLog(@"asset url %@", asseturl); 
    // Try to load asset at mediaURL 
    [library assetForURL:asseturl resultBlock:^(ALAsset *asset) { 
     // If asset doesn't exists 
     if (!asset){ 
      [objectsToRemove addObject:dico]; 
     }else{ 
      [tmpListAsset addObject:[asseturl absoluteString]]; 
      NSLog(@"tmpListAsset : %@", tmpListAsset); 
     } 
    } failureBlock:^(NSError *error) { 
     // Type your code here for failure (when user doesn't allow location in your app) 
    }]; 
} 

Répondre

1

La meilleure chose à faire est de déplacer votre code à l'intérieur (à la fin de) la resultBlock ou failureBlock. Ainsi, votre code s'exécutera dans le bon ordre et vous conserverez également un comportement asynchrone.

+0

Vous voulez dire après l'autre} La chose est que je dois la boucle est terminée et aussi le code qui suit est aa grand morceau de code avec d'autres fonctions ... – Mathieu

+0

async supposer que ce soit en cours d'exécution sur la thread principal, voulez-vous vraiment bloquer tout le thread principal en attendant que ce bloc se termine? –

+0

oui parce que j'appelle ceci avec un execselectorinbackground – Mathieu

44

approche sémaphores GCD:

dispatch_semaphore_t sema = dispatch_semaphore_create(0); 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0); 

for (NSURL *url in self.assetUrls) { 
    dispatch_async(queue, ^{ 
     [library assetForURL:url resultBlock:^(ALAsset *asset) { 
      [self.assets addObject:asset]; 
      dispatch_semaphore_signal(sema); 
     } failureBlock:^(NSError *error) { 
      dispatch_semaphore_signal(sema); 
     }]; 
    }); 
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 
} 
dispatch_release(sema); 

/* Check out ALAssets */ 
NSLog(@"%@", self.assets); 
+4

Notez que si ce code ne doit pas être appelé dans le thread d'arrière-plan (par exemple: using 'performSelectorInBackground:'), car un blocage se produira (les blocs semblent être appelés sur le même thread, donc le sémaphore n'est jamais signalé). –

+1

Cela devrait être la réponse sélectionnée @ Mathieu – brandonscript

4

Notez que assetForURL: resultBlock: failureBlock: sera bloqué si le thread principal attend sans runloop en cours d'exécution. Ceci est une alternative (nettoyeur :-)) solution:

#import <libkern/OSAtomic.h> 

... 

ALAssetsLibrary *library; 
NSMutableArray *assets; 
... 
__block int32_t counter = 0; 
for (NSURL *url in urls) { 
    OSAtomicIncrement32(&counter); 
    [library assetForURL:url resultBlock:^(ALAsset *asset) { 
     if (asset) 
      [assets addObject:asset]; 
     OSAtomicDecrement32(&counter); 
    } failureBlock:^(NSError *error) { 
     OSAtomicDecrement32(&counter); 
    }]; 
} 
while (counter > 0) { 
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; 
} 
+1

Trouvé que ma méthode n'est pas toujours de travail (attente infinie peut arriver). Je suggère la méthode sémaphore GCD shacked qui fonctionne pour moi. –

1

Ceci est un moyen facile de le faire. Peut-être pas aussi élégant que l'utilisation de GCD mais il devrait faire le travail ... Cela va bloquer votre méthode au lieu de non-blocage.

__block BOOL isFinished = NO; 
NSURL *asseturl; 
NSMutableArray *tmpListAsset = [[NSMutableArray alloc] init]; 

ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init]; 
NSMutableArray *objectsToRemove = [[NSMutableArray alloc] init]; 
for (NSDictionary *dico in assetsList) { 
    asseturl = [NSURL URLWithString:[dico objectForKey:@"assetUrl"]]; 
    NSLog(@"asset url %@", asseturl); 
    // Try to load asset at mediaURL 
    [library assetForURL:asseturl resultBlock:^(ALAsset *asset) { 
     // If asset doesn't exists 
     if (!asset){ 
      [objectsToRemove addObject:dico]; 
     }else{ 
      [tmpListAsset addObject:[asseturl absoluteString]]; 
      NSLog(@"tmpListAsset : %@", tmpListAsset); 
     } 
     if (objectsToRemove.count + tmpListAsset.count == assetsList.count) { 
      isFinished = YES; 
     } 
    } failureBlock:^(NSError *error) { 
     // Type your code here for failure (when user doesn't allow location in your app) 
     isFinished = YES; 
    }]; 
} 

while (!isFinished) { 
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01f]]; 
} 
Questions connexes