A 保留週期發生在兩個對象存儲彼此強關聯時。最簡單的情況是存儲對象a
的對象b
和b
的強烈參照做相反的[1]。 Objective-C中保留循環是一個問題,因爲它們讓ARC相信這些對象始終在使用中,即使這些對象沒有從其他地方引用。
讓我們來回顧一些例子。您有分配a
和b
的對象z
,利用它們,然後配置它們。如果a
和b
首先在它們自己之間創建了保留循環,則不會釋放其中的a
和b
。如果你多次這樣做,你會嚴重泄漏記憶。
一個保留週期的另一個現實世界的例子是,如果a
分配和強烈引用b
對象,但你還可以存儲從b
在對象圖a
(許多更小的物體很強的參考可能需要訪問父母 )。
在這些情況下最常見的解決方案是確保包含的對象只包含對其包含對象的弱引用,並確保兄弟對象不包含彼此的強引用。
另一種解決方案(通常不那麼優雅,但在某些情況下可能適用)可能在a
中有某種自定義cleanup
方法,其缺少對b
的引用。因此b
將在調用cleanup
時被釋放(如果b
未在其他地方被強烈引用)。這很麻煩,因爲你不能從a
的dealloc
(如果有保留週期它永遠不會被調用)以及因爲你必須記得在適當的時間呼叫cleanup
。
- 注意,保留週期是也可傳遞(例如,對象
a
強烈引用b
強烈引用c
強烈引用a
)。
有了這一切說:塊的內存管理是相當棘手的理解。
你的第一個例子中可以創建一個臨時保留週期(且僅當您self
對象存儲的強引用someObject
)。當該塊完成執行並釋放後,此臨時保留週期將消失。
在執行過程中,self
將一個參考someObject
,someObject
存儲到block
和block
到self
一次。但是,這只是暫時的,因爲塊不會永久存儲在任何地方(除非[someObject successBlock:failure:]
實現這樣做,但對於完成塊而言不常見)。
因此,在您的第一個示例中,保留週期不是問題。
通常,如果某些對象正在存儲該塊而不是直接執行,則在塊內保留週期只是一個問題。然後很容易看到,self
強烈參考block
,而block
強烈參考self
。請注意,從塊中訪問任何ivar會自動生成該塊中的self
的強引用。
確保包含的對象沒有強烈引用其容器的等價物是使用__weak SelfClass *weakSelf = self
來訪問這兩種方法和ivars(如果通過訪問器訪問ivars,就像使用屬性時一樣)。您的區塊對self
的引用將會很弱(它的不是副本,它是弱引用),並且允許self
在不再強烈引用時解除分配。
有人可能會爭辯說,在所有塊中都使用weakSelf
是好習慣,以防萬一。我想知道爲什麼蘋果沒有把這個默認行爲。這樣做通常不會做任何有害的代碼塊,即使實際上不需要。
__block
上指向對象的變量很少使用,因爲Objective-C的不強制喜歡的對象的不變性。
如果您有一個指向該對象的指針,則可以調用它的方法,並且這些方法可以修改它,無論有沒有__block
。 __block
更適用於基本類型的變量(int,float等)。有關將對象指針變量用於__block
時發生的情況,請參見here。您還可以閱讀Apple的Blocks Programming Topics中__block
的更多信息。
編輯:修正了在對象指針上使用__block
的錯誤。感謝@KevinDiTraglia指出它。
假設MyCLass實現了一個副本,它是一個真正的副本......因爲'-copyWithZone:'可以保留......這是完全合法的,並且可以在任何不可變對象中完成。 –
@GradyPlayer:或許我表達得很糟糕,但我的意思是塊在塊的上下文中用'self'(或'me')的*當前內容*保存一個強(或弱)指針。不涉及'copy' *方法*。 –
是的,當有人對他們做某些事情時,有時候這樣的循環會回到頂端......有時我必須在幾個月或幾年之後纔有一個書呆子挑選......但是可以在塊捕獲時複製對象,所以我不需要認爲這是不正確的... –