2014-06-19 70 views
4

我有一個NSOperationQueue的NSOperation,有一堆子操作,有些排隊。NSOperation。取消與完成狀態

我有一個問題,即使在隊列上調用cancelAllOperations後,我的主要方法掛在waitUntilAllOperationsAreFinished上。

然後,當我設置完成標誌,我使用isFinished取消後不再備份在取消隊列中。

- (BOOL)isFinished 
{ 
    return complete; 
} 

- (void)cancel 
{ 
    cancelled = YES; 
    complete = YES; 
    [_childOperationQueue cancelAllOperations]; 
} 

這是正確的行爲,取消的操作應該在技術上完成? 看起來NSOperation需要將isFinished設置爲true,然後才能將其刪除,因爲這可能允許它「清理」,但我不知道協議在這裏,Google沒有透露太多內容。

+0

您確定您的操作實際上取消了嗎?告訴它取消不會立即取消它,它只是告訴它應該取消它自己的塊。你需要真正檢查'self.cancelled'並放棄你的操作。您不應該重寫'isFinished'或'cancel' - 兩者的默認行爲都應該起作用。 –

+1

@AbhiBeckert如果編寫一個非併發操作,你是對的。但是在編寫併發操作時,你總是重寫'isFinished'方法(顯式地或者自動合成的getter)。此外,重新取消,雖然我同意你一般不會重寫,但是定期檢查'isCancelled',有時你不能這樣做。例如,如果你啓動一個基於塊的'NSURLSessionTask',就沒有你可以檢查'isCancelled'的位置,所以你將在這種情況下覆蓋'cancel'方法。 – Rob

回答

2

取消操作僅設置isCancelled返回YES。這意味着在你的NSOperation塊中,你可以檢查isCancelled,並防止不必要的做任何工作(你需要自己實現這個邏輯)。

您的主線程需要等待隊列上的所有操作,但是如果您的NSOperation塊在執行任何操作之前檢查isCancelled,您應該快速完成所有排隊操作,並且等待時間不應過長。

+0

另請注意,如果一個塊被取消但尚未開始執行,那麼它將永遠不會開始執行 - 它應該立即變爲「已完成」。 –

+1

你確定嗎?我認爲它仍然會被執行,這是你的工作,檢查它是否被取消? –

+1

該文件似乎暗示他們不應該被執行,但我發誓以我的經驗。我想知道主線程是否阻塞等待隊列上的所有內容完成會影響到這一點。 –

2

如果你正在寫一個併發操作(即isConcurrent方法返回YES),我有兩點看法:

  1. 當你改變你的操作的狀態下完成,必須手動進行適當的isFinished KVN。因此,在更改狀態變量之前,請致電willChangeValueForKey,更改之後,請致電didChangeValueForKey

    有很多方法來實現這一點,但我確定我finishedexecuting屬性,像這樣:

    @property (nonatomic, readwrite, getter = isFinished) BOOL finished; 
    @property (nonatomic, readwrite, getter = isExecuting) BOOL executing; 
    

    我使用這些合成的干將,但寫做相應KVN制定者:

    @synthesize finished = _finished; 
    @synthesize executing = _executing; 
    
    - (void)setExecuting:(BOOL)executing 
    { 
        if (_executing != executing) { 
         [self willChangeValueForKey:@"isExecuting"]; 
         _executing = executing; 
         [self didChangeValueForKey:@"isExecuting"]; 
        } 
    } 
    
    - (void)setFinished:(BOOL)finished 
    { 
        if (_finished != finished) { 
         [self willChangeValueForKey:@"isFinished"]; 
         _finished = finished; 
         [self didChangeValueForKey:@"isFinished"]; 
        } 
    } 
    

    然後,當我要完成的操作,我打電話的方法等,以便:

    - (void)completeOperation 
    { 
        self.executing = NO; 
        self.finished = YES; 
    } 
    

    這導致KVN的isExecutingisFinished(以及確保我的合成獲取器也​​返回適當的值)。如果你不這樣做,你的操作可能永遠不會完成。

  2. 在取消操作方面,有兩種做法:

    • 您可以定期檢查[self isCancelled](一種很常見的模式,如果你有一個循環或一些方法正在被反覆調用,例如didReceiveData在基於委託的連接/會話中),如果是,請執行所需的清理,然後還要完成操作(上述completeOperation方法)。

    • 如果你沒有,你可以定期檢查取消狀態的任何地方,你想覆蓋cancel方法,產生任何你需要清理,要求[super cancel]又能保證操作完成後,太(如通話如果操作正在執行,則爲completeOperation)。

    我也有start檢查取消狀態:

    - (void)start 
    { 
        if ([self isCancelled]) { 
         self.finished = YES; 
         return; 
        } 
    
        self.executing = YES; 
    
        // start my operation 
    } 
    

除了上面,很難勸你更不知道多一點什麼在操作的心臟( NSURLConnectionNSURLSession?別的?)。

欲瞭解更多信息,請參閱配置併發執行的操作Concurrency Programming Guide: Operation Queues