Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects. Rather than having to think about retain and release operations [^1]html
[^1]: Transitioning to ARC Release Notesios
ARC提供是一個編譯器的特性,幫助咱們在編譯的時候自動插入管理引用計數的代碼。
最重要的是咱們要認識到ARC的本質仍然是經過引用計數來管理內存。所以有時候若是咱們操做不當,仍然會有內存泄露的危險。下面就總結一下ARC時代可能出現內存泄露的場景。git
循環引用github
基於引用計數的內存管理機制沒法繞過的一個問題即是循環引用(retain cycle)
(Python一樣也採用了基於引用計數的內存管理,可是它採用了另外的機制來清除引用循環致使的內存泄露,而OC和Swift須要咱們本身來處理這樣的問題[^2])app
會致使Block與對象之間的循環引用的狀況有:ide
self.myBlock = ^{ self.someProperty = XXX; };
對於這種Block與Self直接循環引用的狀況,編譯器會給出提示。工具
可是對於有多個對象參與的狀況,編譯器便無能爲力了,所以涉及到block內使用到self的狀況,咱們須要很是謹慎。(推薦涉及到self的狀況,若是本身不是很是清楚對象引用關係,統一使用解決方法處理)this
someObject.someBlock = ^{ self.someProperty = XXX; }; //尚未循環引用 self.someObjectWithABlock = someObject; // 致使循環引用,且編譯器不會提醒
解決方案:spa
__weak SomeObjectClass *weakSelf = self; SomeBlockType someBlock = ^{ SomeObjectClass *strongSelf = weakSelf; if (strongSelf == nil) { // The original self doesn't exist anymore. // Ignore, notify or otherwise handle this case. } [strongSelf someMethod]; };
咱們還有一種更簡便的方法來進行處理,實際原理與上面是同樣的,但簡化後的指令更易用。code
@weakify(self)
[self.context performBlock:^{ // Analog to strongSelf in previous code snippet. @strongify(self) // You can just reference self as you normally would. Hurray. NSError *error; [self.context save:&error]; // Do something }];
你能夠在這裏找到@weakify,@strongify工具:MyTools_iOS
[^2]: How does Python deal with retain cycles?
NSTimer
通常狀況下在action/target模式裏 target通常都是被weak引用,除了NSTimer。
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats
在官方文檔中:
target
The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to this object until it (the timer) is invalidated.
Timer Programming Topics :
A timer maintains a strong reference to its target. This means that as long as a timer remains valid, its target will not be deallocated. As a corollary, this means that it does not make sense for a timer’s target to try to invalidate the timer in its dealloc method—the dealloc method will not be invoked as long as the timer is valid.
舉一個例子,一個Timer的Target是ViewController.
這個時候,若是咱們是在dealloc方法裏讓timer invalidate,就會形成內存泄露.
事實上,timer是永遠不會被invalidate.由於此時VC的引用計數永遠不會爲零。由於Timer強引用了VC。而由於VC的引用計數不爲零,dealloc永遠也不會被執行,因此Timer永遠持有了VC.
所以咱們須要注意在什麼地方invalidate計時器,咱們能夠在viewWillDisappear裏面作這樣的工做。