【问题标题】:Wait for assetForURL blocks to be completed等待assetForURL块完成
【发布时间】:2011-11-06 06:14:37
【问题描述】:

我想等待这段代码执行后再继续,但由于这些块是异步调用的,我不知道该怎么做???

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

【问题讨论】:

    标签: iphone objective-c alasset alassetslibrary


    【解决方案1】:

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

    【讨论】:

    • 注意如果这段代码不应该在后台线程中调用(例如:使用performSelectorInBackground:),因为会发生死锁(块似乎是在同一个线程上调用的,所以信号量永远不会发出信号)。
    • 这应该是选择的答案@Mathieu
    【解决方案2】:

    这是一种简单的方法。也许不如使用 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]];
    }
    

    【讨论】:

      【解决方案3】:

      注意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]];
      }
      

      【讨论】:

      • 发现我的方法并不总是有效(可能会出现无限等待)。我建议使用适用于我的 shacked 的 GCD 信号量方法。
      【解决方案4】:

      【讨论】:

      • 这是一个仅链接的答案,应该通过包括源文章中的相关代码和现代化来改​​进(因为这个答案现在已经 4 岁了)。
      【解决方案5】:

      最简单的做法是将代码移动到resultBlockfailureBlock 内部(末尾)。这样,您的代码将以正确的顺序运行,并且您还将保留异步行为。

      【讨论】:

      • 你的意思是在 else 之后
      • 假设这是在主线程上运行,你真的要在等待这个块完成的同时阻塞整个主线程吗?
      猜你喜欢
      • 2013-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 2020-10-04
      • 2020-07-04
      • 2011-12-28
      相关资源
      最近更新 更多