我是块的新手,我正在尝试弄清楚如何在执行我的操作之前等待块完成(在这种情况下是一个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);
}];
}
答案 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){};