2014-01-06 107 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){}; 
相關問題