2011-08-29 21 views
24

Me gustaría esperar a que se ejecute este código antes de continuar, pero como estos bloques se llaman de forma asíncrona, no sé cómo hacerlo ???Espere a que se completen los bloques de assetForURL

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

Respuesta

1

La cosa más fácil que hacer es mover el código para el interior (al final de) la resultBlock o la failureBlock. De esta forma, su código se ejecutará en el orden correcto y también conservará el comportamiento asincrónico.

+0

¿Quieres decir después del else} Lo que pasa es que necesito el bucle para ser terminado y también el código que está siguiendo es aa gran trozo de código con otras funciones asíncronas ... – Mathieu

+0

suponiendo que ésta esté ejecutando en el hilo principal, ¿realmente quieres bloquear todo el hilo principal mientras esperas a que este bloque termine? –

+0

yes porque llamo esto con un performselectorinbackground – Mathieu

44

GCD enfoque de semáforos:

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

tenga en cuenta que si este código no debe invocarse en el hilo de fondo (por ejemplo: utilizando 'performSelectorInBackground:'), ya que se producirá un interbloqueo (los bloques parecen ser llamados en el mismo hilo, por lo que el semáforo nunca se señaliza). –

+1

Esta debería ser la respuesta seleccionada @Mathieu – brandonscript

4

Tenga en cuenta que assetForURL: resultBlock: failureBlock: se bloquean si el hilo principal está a la espera sin Runloop corriendo. Esta es una solución alternativa (limpiador :-)):

#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

Encontré que mi método no siempre funciona (puede haber una espera infinita). Sugiero el método de semáforo GCD de shacked, que funciona para mí. –

1

Esta es una manera fácil de hacerlo. Tal vez no sea tan elegante como usar GCD pero debería hacer el trabajo ... Esto hará que su método bloquee en lugar de no bloquear.

__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]]; 
} 
Cuestiones relacionadas