2011-10-13 151 views
28

使用ARC處理目標爲4.0和5.0的iOS項目。ARC,塊和保留週期

遇到與塊,ARC和塊外部引用對象相關的問題。下面是一些代碼:

__block AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
    [operation setCompletionBlock:^ { 
     if ([operation isCancelled]) { 
      return; 
     } 

... do stuff ... 

operation = nil; 
}]; 

在這種情況下,編譯器會發出警告,在塊是用「操作」將會導致保留週期。在ARC下,__block現在保留該變量。

如果我添加__unsafe_unretained,編譯器會立即釋放對象,所以很明顯,這是行不通的。

我針對4.0,所以我不能使用__weak。

我試圖做這樣的事情:

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
__block __unsafe_unretained AFHTTPRequestOperation *weakOperation = operation; 

但同時weakOperation不爲零,沒有它的屬性被填充時,塊內。

考慮到上面列出的項目限制,處理這種情況的最佳方法是什麼?

回答

23

假設進度保證,保留週期可能正是你想要的。你明確地在塊的末尾打破了保留週期,所以它不是一個永久的保留週期:當塊被調用時,週期被打破。

但是,如果您還有其他操作可以保留操作,則可以將參考存儲到__weak__unsafe_unretained變量中,然後使用塊中的參考。除非由於某種原因需要在塊中更改變量的綁定,否則不需要__block - 對變量進行限定;由於您沒有保留週期來破壞,所以您不需要爲弱變量分配任何內容。

+1

我已經有了'沒有保留週期'的東西,我甚至都沒有按照你描述的方式去思考。咄。下一個問題 - 任何方式來沉默編譯器警告?它會讓我發瘋。 – Hunter

+1

請參閱Clang用戶手冊中的[「通過Pragma控制診斷」](http://clang.llvm.org/docs/UsersManual.html#diagnostics_pragmas)。你只需要弄清楚哪個警告標誌要忽略。 –

+4

這是'#pragma clang diagnostic ignored'-Warc-retain-cycles「',由by。 –

1

這似乎是由康拉德·斯托爾在Blocks, Operations, and Retain Cycles描述的問題,但他的書面記錄錯過了幾個要點:

  • __block貌似避免在MRC捕獲變量很強的參考的蘋果推薦的方式模式,但在ARC模式下完全沒有必要。在這種情況下,在ARC模式下完全沒有必要;也正是在MRC模式不必要雖然重量更輕的解決辦法是更詳細:void * unretainedOperation = operation; ... ^{ AFHTTPRequestOperation * op = unretainedOperation; }
  • 在ARC模式下,你既需要很強的參考(這樣你就可以將其添加到隊列)和弱/ unsafe_unretained參考

最簡單的辦法是這樣的:

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
AFHTTPRequestOperation * __unsafe_unretained unretainedOperation = operation; 

[operation setCompletionBlock:^ { 
    if ([unretainedOperation isCancelled]) { 
    return; 
    } 
    ... do stuff ... 
}]; 

即使你打破參考週期,沒有理由阻止保留AFHTTPRequestOperation擺在首位(假設操作會保持自身活着直到t他完成處理程序完成,這並不總是保證但通常如果使用ARC進一步調用堆棧上的self引用由ARC假定和假定。

最好的修復程序似乎是更新到latest AFNetworking,它將操作作爲參數傳遞到塊中。

+0

__block不是完全不必要的。默認情況下,所有由塊保留的變量都是const內部的,所以你不能改變它們的值。這裏__block來拯救。 –