2011-08-29 122 views
24

我想等待这段代码被执行之前继续,但因为这些块是异步调用,我不知道该怎么办?等待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) 
    }]; 
} 

回答

1

最简单的事情做的是你的代码移动到内(在月底)的resultBlockfailureBlock。这样,您的代码将以正确的顺序运行,并且您还将保持异步行为。

+0

你的其他后平均} 的事情是我需要的循环中完成,也被下面的代码是AA大块的代码与其他异步功能... – Mathieu

+0

假设这是在运行主线程,你真的想阻止整个主线程,而等待这个块完成? –

+0

是的,因为我用performselectorinbackground调用了这个 – Mathieu

44

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

请注意,如果不应该在后台线程中调用此代码(例如:使用'performSelectorInBackground:'),由于会发生死锁(这些块似乎在同一个线程中调用,所以信号从未被发信号)。 –

+1

这应该是选定的答案@Mathieu – brandonscript

4

注意assetForURL:resultBlock:failureBlock:如果主线程等待不RunLoop运行后会卡住。这是替代(清洁:-))解决方案:

#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

发现我的方法不总是工作(可能发生无限的等待)。我建议Shacked的GCD信号量方法适用于我。 –

1

这是一个简单的方法来做到这一点。也许不如使用GCD那样优雅,但它应该完成工作......这将使您的方法阻塞,而不是非阻塞。

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