2014-01-06 112 views
2

我是新来的块,并且正在尝试弄清楚如何在执行我的操作之前等待块完成(在这种情况下为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

您要拨打'的NSLog(@ “convertedPhotos ::%@”,convertedImages);'当每一个图像已经被处理? – Jkmn

+0

通常你会把代码放在块的末尾...... – Wain

+0

@Jkmn是的,这是正确的。 – BluGeni

回答

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); 
}); 
+0

你能告诉我这是怎么回事吗? – BluGeni

+0

@BluGeni更新了我的回答 – Andy

+0

@BlueGeni我再次更新我的答案,以使用信号量而不是组,因为在这里更合适。 – Andy

2

最好的选择是不直接使用块调用。相反,创建NSBlockOperation的实例并将它们添加到操作队列中。然后再创建一个NSBlockOperation并使其依赖于所有其他操作。这可确保上次操作只在所有其他操作完成后才运行,并允许您控制同时运行多少个操作。

如果您有嵌套的块调用或某些无法更改以启用此功能的API,那么如果创建NSOperation子类,则仍可以执行此操作,以便在所有异步操作完成之前操作无法完成。看看dribin.org concurrent operations

+0

这是你在说什么? http://stackoverflow.com/questions/4326350/how-do-i-wait-for-an-asynchronously-dispatched-block-to-finish – BluGeni

+0

你可以尝试一个基于信号量的解决方案,但你仍然需要知道哪个是最后一个(所以它应该发信号)或有一个计数信号量(因此所有信息在发布之前完成)。 – Wain

+0

你知道计数,所以你可以用它创建'dispatch_semaphore_create' ... – Wain

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

如果你想等待主队列异步执行任务是 - 你不会可能希望在等待信号量时阻止它。 我使用这种结构,它不冻结UI 只为主队列

__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){}; 
相关问题