在执行某事之前等待完成块

时间:2014-01-06 14:43:00

标签: ios objective-c

我是块的新手,我正在尝试弄清楚如何在执行我的操作之前等待块完成(在这种情况下是一个nslog)所以我怎么能等到块完成之后再在代码中执行这个nslog下面:NSLog(@"convertedPhotos::%@",convertedImages);

          convertedImages =  [[NSMutableArray alloc] init];
        for (NSDictionary *photo in photos) {
            // photo is a dictionary containing a "caption" and a "urlRep"
            [photoUrls addObject:photo[@"urlRep"]];
        }

        if (photoUrls.count) {
            for (id photos in photoUrls){
                NSString *urlString = photos;
                [self base64ImageAtUrlString:urlString result:^(NSString *base64) {


                    [jsonWithPhotos setObject:convertedImages forKey:@"photo64"];
                    NSError *error;
                    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonWithPhotos
                                                                       options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
                                                                         error:&error];

                    if (! jsonData) {
                        NSLog(@"Got an error: %@", error);
                    } else {
                        NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
                        NSLog(@"json::%@",jsonString);

                    }
                }];
            }
        }
        else {
            NSLog(@"where are my urls?");
        }
        NSLog(@"convertedPhotos::%@",convertedImages);

    }

}

从上面调用此方法/块

- (void)base64ImageAtUrlString:(NSString *)urlString result:(void (^)(NSString *))completion {
    NSURL *url = [NSURL URLWithString:urlString];
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

    [library assetForURL:url resultBlock:^(ALAsset *asset) {

        // borrowing your code, here... didn't check it....
        ALAssetRepresentation *representation = [asset defaultRepresentation];
        CGImageRef imageRef = [representation fullResolutionImage];

        //TODO: Deal with JPG or PNG
        NSData *imageData = UIImageJPEGRepresentation([UIImage imageWithCGImage:imageRef], 0.1);
        NSString *base64 = [imageData base64EncodedString];
        completion(base64);
        [convertedImages addObject:base64];

//        NSLog(@"converted::%@",convertedImages);

    } failureBlock:^(NSError *error) {
        NSLog(@"that didn't work %@", error);
    }];
}

3 个答案:

答案 0 :(得分:5)

我会使用NSOperationQueue(或调度队列)和NSCondition(或调度组)来等待操作完成。如果使用内存消耗对象(如NSData),在@autoreleasepool中包装块以刷新内存也很重要。

示例:

// create results array
__block NSMutableArray* results = [NSMutableArray new];

// create serial queue
dispatch_queue_t queue = dispatch_queue_create("myQueue", 0);

for(NSInteger i = 0; i < 10; i++) {
    // enqueue operation in queue
    dispatch_async(queue, ^{
        // create semaphore
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);

        // do something async, I do use another dispatch_queue for example
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            // wrap in autoreleasepool to release memory upon completion
            // in your case wrap the resultBlock in autoreleasepool
            @autoreleasepool {
                // here for example the nested operation sleeps for two seconds
                sleep(2);

                // add the operation result to array
                // I construct an array of strings for example
                [results addObject:[NSString stringWithFormat:@"Operation %d has finished.", i]];

                // signal that nested async operation completed
                // to wake up dispatch_semaphore_wait below
                dispatch_semaphore_signal(sema);
            }
        });

        // wait until the nested async operation signals that its finished
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

        NSLog(@"Finished single operation.");
    });
}

// will be called once all operations complete
dispatch_async(queue, ^{
    NSLog(@"Finished all jobs.");
    NSLog(@"Results: %@", results);
});

答案 1 :(得分:2)

您最好的选择是不要直接使用块。而是创建NSBlockOperation的实例并将它们添加到操作队列中。然后再创建一个NSBlockOperation并使其依赖于所有其他操作。这可以确保最后一个操作仅在所有其他操作完成后运行,并允许您控制一次运行的操作数。

如果你有嵌套的块调用,或者你无法更改的某些API来启用它,那么如果你创建一个NSOperation子类,你仍然可以这样做,直到所有异步操作都没有完成操作完成。看看dribin.org concurrent operations

答案 2 :(得分:2)

对于任何非主队列,请使用信号量

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // some serious stuff here
    ...        
    dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

如果您想等待主队列中的异步任务执行 - 您可能不希望在等待信号量时阻止它。 我使用的结构不会冻结主要队列的

__block BOOL flag = NO;
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // some serious stuff here
    ...        
    flag = YES;
});
// Run until 'flag' is not flagged (wait for the completion block to finish executing
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) && !flag){};