block
typedef void (^TestCircleBlock)();
@property (nonatomic, copy) TestCircleBlock testObject;
block在copy時都會對block內部用到的對象進行強引用的。
self.testObject.testCircleBlock = ^{
[self doSomething];
};
self將block作為自己的屬性變量,而在block的方法體里面又引用了 self 本身,此時就很簡單的形成了一個循環引用。
應該將 self 改為弱引用
__weak typeof(self) weakSelf = self;
self.testObject.testCircleBlock = ^{
__strong typeof (weakSelf) strongSelf = weakSelf;
[strongSelf doSomething];
};
在 ARC 中,在被拷貝的 block 中無論是直接引用 self 還是通過引用 self 的成員變量間接引用 self,該 block 都會 retain self。
我們發現上述這個方法確實解決所有問題,但是可能會有兩個不理解的點:
即使用weakSelf又使用strongSelf,這么做和直接用self有什么區別?
為什么不會有循環引用?
這是因為block外部的weakSelf是為了打破環循環引用,而block內部的strongSelf是為了防止weakSelf被提前釋放,strongSelf僅僅是block中的局部變量,在block執行結束后被回收,不會再造成循環引用。
這么做和使用weakSelf有什么區別?
唯一的區別就是多了一個strongSelf,而這里的strongSelf會使self的引用計數+1,使得self只有在block執行完,局部的strongSelf被回收后,self才會dealloc。
delegate
在委托問題上出現循環引用問題已經是老生常談了,規避該問題的殺手锏也是簡單到哭:聲明delegate時請用assign
(MRC)或者weak
(ARC),千萬別手賤玩一下retain
或者strong
,畢竟這基本逃不掉循環引用了!
delegate 屬性的聲明如下:
@property (nonatomic, weak) id <TestDelegate> delegate;
如果將 weak 改為 strong,則會造成循環引用
// self -> ViewController
ViewController *vc = [ViewController new];
vc = self;
[self.navigationController pushViewController: vc animated:YES];
// 假如是 strong 的情況
// bVc.delegate ===> ViewController (也就是 A 的引用計數 + 1)
// ViewController 本身又是引用了 <ViewControllerDelegate> ===> delegate 引用計數 + 1
// 導致: ViewController <======> Delegate ,也就循環引用啦