Дождитесь завершения блоков 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)
    }];
}
24
задан Mathieu 29 August 2011 в 18:47
поделиться

3 ответа

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);
44
ответ дан 28 November 2019 в 22:56
поделиться

Обратите внимание, что assetForURL: resultBlock: failBlock: зависнет, если основной поток ожидает без запуска 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]];
}
4
ответ дан 28 November 2019 в 22:56
поделиться

Это простой способ сделать это. Может быть, не так элегантно, как использование 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]];
}
1
ответ дан 28 November 2019 в 22:56
поделиться