2012-08-09 52 views
1

我有一個要處理的對象數組。這些對象有如下方法調度隊列,併發和完成處理

@interface CustomObject : NSObject 

- (void)processWithCompletionBlock:(void (^)(BOOL success))completionBlock; 

@end 

每個對象的處理需要不同的時間,並可能有不同的結果。並且已知處理本身正在同時執行。說實話,限制併發操作的數量是非常好的,因爲它們非常密集。

所以我需要枚舉該數組對象,並對其進行處理。如果某些對象處理失敗,我需要跳過所有其餘的對象。當然,我需要在枚舉和處理所有對象後收到通知。

它應該通過創造NSOperationQueueNSOperation子類來解決?這個班級如何能夠滿足這些要求?還有其他一些優雅的方法嗎?

回答

0

好的。爲了幫助他人理解如何處理這種方法,我分享了我自己的代碼。

爲了限制併發線程的數量,我們可以調用-(void)setMaximimumConcurrentOperationCount:方法的NSOperationQueue實例。

要迭代的對象,並提供完成的機制,我們可以定義如下方法:

- (void)enumerateObjects:(NSArray *)objects 
{ 
    // define the completion block 
    NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{ 
     NSLog(@"Update UI"); 
    }]; 

    // register dependencies 
    for (CustomObject *obj in objects) { 
     CustomOperation *operation = [[CustomOperation alloc] initWithCustomObject:obj]; 
     [completionOperation addDependency:operation]; // set dependencies for the completion block 
     [_operationQueue addOperation:operation]; 
    } 

    // register completionOperation on main queue to avoid the cancellation 
    [[NSOperationQueue mainQueue] addOperation:completionOperation]; 
} 

覆蓋的NSOperation子類的- (void)start方法來啓動我們的自定義操作:

- (void)start 
{ 
    // We need access to the operation queue for canceling other operations if the process fails 
    _operationQueue = [NSOperationQueue currentQueue]; 

    if ([self isCancelled]) { 
     // Must move the operation to the finished state if it is canceled. 
     [self willChangeValueForKey:@"isFinished"]; 
     _finished = YES; 
     [self didChangeValueForKey:@"isFinished"]; 
     return; 
    } 

    [self willChangeValueForKey:@"isExecuting"]; 
    // We do not need thread detaching because our `-(void)processWithCompletionBlock:` method already uses dispatch_async 
    [self main]; // [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil]; 
    _executing = YES; 
    [self didChangeValueForKey:@"isExecuting"]; 

} 

覆蓋的- (void)mainNSOperation子類的方法來處理我們的自定義對象:

- (void)main 
{ 
    @try { 
     NSLog(@"Processing object %@", _customObject); 
     [_customObject processWithCompletionBlock:^(BOOL success) { 
      _processed = success; 
      if (!success) { 
       NSLog(@"Cancelling other operations"); 
       [_operationQueue cancelAllOperations]; 
      } 
      [self completeOperation]; 
     }]; 
    } 

    @catch (NSException *exception) { 
     NSLog(@"Exception raised, %@", exception); 
    } 
} 

感謝名單,以@Rob指着我出去缺少的一部分。

1

這正是NSOperation是專爲。派遣隊列是更低級別的處理程序,並且您必須構建許多您需要的部分。你當然可以這樣做(NSOperationQueue是建立在GCD之上的),但你會重塑NSOperation

您可以處理大部分NSOperation兩種方式。如果很簡單,你可以創建一個NSBlockOperation。如果情況稍微複雜一點,您可以繼承NSOperation並覆蓋main方法來完成您想要的操作。

有幾種方法可以取消所有其他操作。您可以爲每個組分配一個單獨的操作隊列。然後,您可以輕鬆地撥打cancelAllOperations關閉所有內容。或者你可以有一個單獨的控制器,知道相關操作的列表,它可以調用cancel

請記住,「取消」僅僅意味着「不按期如果還沒有盯着,並設置isCancelled如果它。」它不會中止正在運行的操作。如果您想中止正在運行的操作,該操作需要定期檢查isCancelled

通常,您應該限制併發操作隊列將運行的數量。使用setMaximimumConcurrentOperationCount:

有兩種方法可以確定所有操作都已完成。您可以進行額外的操作(通常爲BlockOperation),並使用addDependency:使其依賴於所有其他操作。這是一個很好的異步解決方案。如果您可以處理同步解決方案,那麼您可以使用waitUntilAllOperationsAreFinished。我通常更喜歡前者。

+0

怎麼這個類可以看看滿足這些要求? – voromax 2012-08-09 01:15:19

+0

對於'addDependency:'+1。我真的很想念它。 – voromax 2012-08-09 01:43:09

+0

Rob Napier,你如何在BlockOperations上使用addDependency? – 2014-10-30 20:05:53

1

使用NSOperationQueue,使您的類中的NSOperation

使用此方法來排隊你的工作

- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait 

到操作隊列的引用添加到您創建的NSOperation子類

如果錯誤在NSOperationQu發生致電

- (void)setSuspended:(BOOL)suspend 

eue

+0

你是不是指' - (void)setCancelled'? :) – voromax 2012-08-09 01:09:38

+0

沒有setCancelled上NSOperationQueue,或NSOperation有一個cancelAllOperations雖然這將工作正常。 – 2012-08-09 01:13:20

+0

這個班級如何能夠滿足這些要求? – voromax 2012-08-09 01:15:52