2014-01-07 55 views
2

我正在搞一個爛攤子,並試圖找出一個熟練的方式來處理這個問題,但我陷入困境。我現在的問題是,在我希望它們成爲代碼之前,我已經執行了代碼,它必須處理我的代碼塊。塊內的塊不知道該怎麼辦

下面的代碼的問題在於postToForm方法正在被調用並在我的convertedImages被添加到之前執行。我該如何解決這個問題,以便它等待發生?或者我是以這種錯誤的方式去做的? (我需要知道的內存使用太多,需要釋放內存後作出後)。

這裏是我的代碼包含問題:

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

// create dispatch group 
dispatch_group_t group = dispatch_group_create(); 

for(id photos in photoUrls) { 
    NSString *urlString = photos; 

    // enqueue operation in queue 
    dispatch_async(queue, ^{ 
     // enter the group 
     dispatch_group_enter(group); 

     // 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 
      @autoreleasepool { 
       // here for example the nested operation sleeps for two seconds 
       NSURL *url = [NSURL URLWithString:urlString]; 
       ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; 

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

        //TODO: Deal with JPG or PNG 
        NSData *imageData = UIImageJPEGRepresentation([self thumbnailForAsset:asset maxPixelSize:1000], 0); 
        NSString *base64 = [imageData base64EncodedString]; 
        NSLog(@"base64::%@",base64); 
        [convertedImages addObject:base64]; 

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


       dispatch_group_leave(group); 
      } 
     }); 

     // wait until the nested async operation leaves the group (e.g finishes its job) 
     dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 

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

// will be called once all operations complete 
dispatch_async(queue, ^{ 
    NSLog(@"Finished all jobs. "); 
    NSLog(@"how many::%lu",(unsigned long)convertedImages.count); 
    [jsonWithPhotos setObject:convertedImages forKey:@"photo64"]; 
    [self postToForm]; 
}); 

回答

4

之所以在此之前,所有的圖像加載的是,你在呼喚在錯誤的地方dispatch_group_leave(group);您完成塊被調用。您應該在ALAssetsLibrary的結果塊(和錯誤塊)中調用它。剩下的就是正確的(其實是完全一樣的蘋果建議執行隊列的完成塊:由於GCD的專用隊列是連續,完成塊是什麼更多的隊列本身的最後一個塊)。

編輯︰問: 事實是,ALAssetsLibrary需要一段時間來提取所請求的網址(實際上有一個完成塊,提示操作是異步)的數據。於是立即請求圖像當前URL後,你被釋放被dispatch_group_enter,也許這是發生之前ALAssetsLibrary可以執行完畢塊中創建的信號。

現在,記住,你是如何實現的隊列的完成塊的有效期爲串行隊列只,從iOS 5以上,你可以通過指定DISPATCH_QUEUE_CONCURRENT的隊列類型,有這個創建併發隊列(如全球隊列中)一種方法不再有效。如果不是在這種情況下有一個併發隊列,而是有一個串行隊列,我會檢查當前url是否是ALAssetsLibrary結果塊中的最後一個,並在那裏調用完成塊。

爲了完整起見,您可以使用dispatch_semaphore_t來處理這種情況,這在邏輯上比使用組等待(這裏您的組由1個操作組成)更正確,但是我再說一遍,只是邏輯上更好,結果是一樣的。

一切我寫是寫在Apple's concurrency programming guide

+0

哦,我花了這麼多時間在這個簡單的答案!小心解釋爲什麼它能正確工作? – BluGeni

-1

如果你有依賴性,你」我想要使​​用NSOperationQueues。通過操作隊列,您可以設置操作之間的依賴關係,以便一個(或多個)操作在特定操作完成之前不會執行。

所以,例如,使用塊(就像你擁有的塊),你可以像下面這樣實現它。

NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{ /* your work */ }]; 
NSBlockOperation* dependentOperation = [NSBlockOperation blockOperationWithBlock:^{ /* dependent work */ }]; 

[dependentOperation addDependency:operation]; 

NSOperationQueue* q = [[NSOperationQueue alloc] init]; 
[q addOperations:@[ operation, dependentOperation] waitUntilFinished:NO]; 

NSOperationQueues也給你買了幾個巧妙的事情,如能夠處理取消,這可以派上用場,如果你擔心,如果有故障別處取消postToForm。

如果你擔心內存,你可以設置併發操作的最大數目爲您NSOperationQueue的一部分。

q.maxConcurrentOperationCount = 5; 
+0

這是否意味着我需要做塊以不同的方式或者我可以與我有什麼執行NSOperationQueues? – BluGeni

+0

如果我正確理解你的代碼,我相信你可以創建所有的圖像操作操作,然後進行最後的操作。您可以爲後置操作設置依賴關係,以依賴所有圖像操作操作。圖像處理操作將包括autoreleasepool內的所有內容。這是否回答你的問題? – Travis

0

如果您想對所有這些使用dispatch_async,那麼您將必須以不同的方式工作。形成我可以告訴你只是試圖在背景中做所有這些。有幾種不同的方法可以做到這一點,但是我看到你的代碼在後臺線程中的一個塊中,然後在完成時回調。這也將是最有效的內存(不胃脹),因爲它一次,而不是試圖做一次全部和填滿你的可用內存(並可能崩潰)運行一次轉換。

dispatch_async into queue 
{ 

    for loop to do all of your images 
    { 

    } 

    dispatch_async into main thread saying finished queue 
    { 
     //function call or block with executing code 
    } 
} 

包裝所有的,在一個autoreleasepool只爲增加的內存管理的樂趣。

0

何必運行在循環作爲一個單獨的異步工作各項任務?將整個循環作爲單個任務運行,並在該完成處理程序中將主線程上的函數調用到postToForm。

喜歡的東西

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 
             (unsigned long)NULL), ^(void) { 
     [self convertImages]; 

    }); 

    // Call this on background thread 
    - (void)convertImages { 

     for(id photos in photoUrls) { 
     // Do stuff 
     } 

     // Now call function on main thread 
     [[NSOperationQueue mainQueue] addOperationWithBlock:^ { 
       [self updateUI]; 
     }]; 
    } 

    // Must call this on main thread because we update the UI 
    - (void)updateUI { 
      NSLog(@"Finished all jobs. "); 
      NSLog(@"how many::%lu",(unsigned long)convertedImages.count); 
      [jsonWithPhotos setObject:convertedImages forKey:@"photo64"]; 
      [self postToForm]; 
    } 
相關問題