Wait for assetForURL blocks to be completed

前端 未结 5 2086
离开以前
离开以前 2020-12-23 11:57

I would like to wait this code to be executed before to continue but as these blocks are called assynchronously I don\'t know how to do???

NSURL *asseturl;
N         


        
相关标签:
5条回答
  • 2020-12-23 12:40

    The easiest thing to do is to move your code to inside (at the end of) the resultBlock or the failureBlock. That way, your code will run in the correct order, and you will also retain asynchronous behaviour.

    0 讨论(0)
  • 2020-12-23 12:44

    The solution is here http://omegadelta.net/2011/05/10/how-to-wait-for-ios-methods-with-completion-blocks-to-finish/

    0 讨论(0)
  • 2020-12-23 12:57

    GCD semaphore approach:

    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);
    
    0 讨论(0)
  • 2020-12-23 13:01

    This is an easy way to do it. Maybe not as elegant as using GCD but it should get the job done ... This will make your method blocking instead of non-blocking.

    __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]];
    }
    
    0 讨论(0)
  • 2020-12-23 13:03

    Note that assetForURL:resultBlock:failureBlock: will stuck if the main thread is waiting without RunLoop running. This is alternative ( cleaner :-) ) 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]];
    }
    
    0 讨论(0)
提交回复
热议问题