11

我很難將一些NSOperation代碼轉換爲ARC。我的操作對象使用一個完成塊,它包含一個GCD塊,用於更新主線程上的UI。因爲我從它自己的完成塊中引用我的操作對象,所以我使用__weak指針來避免內存泄漏。但是,我的代碼運行時指針已經設置爲零。在自己的完成塊中引用一個NSOperation對象與ARC

我已經縮小到這個代碼示例。任何人都知道我錯了什麼地方,並且有正確的方法來完成這件事?

NSOperationSubclass *operation = [[NSOperationSubclass alloc] init]; 
__weak NSOperationSubclass *weakOperation = operation; 

[operation setCompletionBlock:^{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 

     // fails the check 
     NSAssert(weakOperation != nil, @"pointer is nil"); 

     ... 
    }); 
}]; 
+1

那麼,錯誤的是一個弱指針不擁有所有權。如果沒有別的東西持有這個變量(並且沒有),它將被清除。如果你使用'operation',你確定會發生泄漏嗎?它看起來應該在完成塊被釋放時消失,它應該在它被調用後立即消失。 (雖然這可能是天真的。) – 2012-02-10 05:59:29

+0

ARC在編譯時抱怨它。沒有它,我直接使用操作指針(並且我不相信我正在泄漏內存)。 – 2012-02-10 06:29:17

+1

祝你好運。我認爲在放棄和做其他事情之前,我已經掙扎了好幾個小時。但已經有一段時間了。 :) – 2012-02-10 16:30:29

回答

10

我不能肯定這一點,但做正確的做法是對可能在__block塊的末尾添加到有問題的變量,然後將其設置爲nil,以確保它是釋放。 See this question.

你的新代碼應該是這樣的:

NSOperationSubclass *operation = [[NSOperationSubclass alloc] init]; 
__block NSOperationSubclass *weakOperation = operation; 

[operation setCompletionBlock:^{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 

     // fails the check 
     NSAssert(weakOperation != nil, @"pointer is nil"); 

     ... 
     weakOperation = nil; 
    }); 

}]; 
+3

你是對的我相信。謝謝! – 2012-02-12 02:02:55

14

另一種選擇是:

NSOperationSubclass *operation = [[NSOperationSubclass alloc] init]; 
__weak NSOperationSubclass *weakOperation = operation; 

[operation setCompletionBlock:^{ 
    NSOperationSubclass *strongOperation = weakOperation; 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     assert(strongOperation != nil); 
     ... 
    }); 
}]; 

[operationQueue addOperation:operation]; 

我想你還可以添加操作對象的NSOperationQueue。在這種情況下,隊列正在保留一個操作。它也可能在執行完成塊時保留它(儘管我還沒有找到關於完成塊的官方確認)。

但是在你裏面完成塊創建另一個塊。該塊將在稍後的某個時間點運行,可能在NSOperations的完成塊運行結束後。發生這種情況時,隊列中將釋放operationweakOperation將爲nil。但是,如果我們從操作的完成塊中爲同一個對象創建另一個強引用,那麼當第二個塊運行時,我們將確保operation存在,並避免保留週期,因爲我們沒有捕獲該塊的operation變量。

Apple在Transitioning to ARC Release Notes中提供了此示例,請參閱中的最後一個代碼片段使用生命週期限定符以避免強參考週期部分。

+4

+1這是正確的答案。'NSOperation'保留了完成塊,所以在完成塊中使用一個弱引用是安全的,因爲它保證了活着。然而,OP的問題在於他們在第二個塊中使用它,稍後執行,並且弱參考不保證在那裏存在。正確的解決辦法是讓第二個塊對'NSOperation'有很強的參考 – user102008 2013-04-02 01:38:07

4

接受的答案是正確的。但是沒有必要weakify操作的iOS 8 /的Mac OS 10.10:

報價從NSOperation documentation on @completionBlock

在iOS系統中8和更高版本以及OS X v10.10及更高版本,此屬性設置在完成塊開始執行之後爲零。

另請參見皮特斯坦伯格的this tweet

相關問題