需要:pod 'YYKit' 在block語句塊中,如果需引用self,而self對象中又持有block對象,就會造成迴圈引用迴圈引用(retain cycle),導致記憶體泄露,比如以下代碼 一般我們是這麼解決的,使用一個__weal修飾的weakSelf變數指向self對象,在block中使用we ...
需要:pod 'YYKit'
在block語句塊中,如果需引用self,而self對象中又持有block對象,就會造成迴圈引用迴圈引用(retain cycle)
,導致記憶體泄露,比如以下代碼
self.block = ^{
[self description];
};
一般我們是這麼解決的,使用一個__weal
修飾的weakSelf變數指向self對象,在block中使用weakSelf:
__weak typeof(self) weakSelf = self; self.block = ^{
[weakSelf description]; };
但是醬紫寫,還是可能出問題,因為weakSelf是弱引用,而self一旦釋放了,weakSelf可能為nil,還是舉個慄子吧:
先定義一個TestObj對象,他的屬性有一個block對象
@interface TestObj : NSObject@property (nonatomic, copy)void(^block)();@end@implementation TestObj- (void)dealloc { NSLog(@"%s",__func__);}- (instancetype)init { self = [super init]; if (self) { __weak typeof(self) weakSelf = self; self.block = ^{ dispatch_async(dispatch_get_global_queue(0, 0), ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"%@",weakSelf); }); }; } return self; } @end
執行testFunc
方法,結果是列印的是(null),因為block里列印的方法是非同步執行的,在 NSLog(@"%@",weakSelf);
這句代碼執行之前testFunc
函數就結束,所以obj
對象已經被release了。
怎麼解決呢?所以再對weakSelf
做一次 __strong
就可以了:
__weak typeof(self) weakSelf = self; self.block = ^{ __strong typeof(weakSelf) strongSelf = weakSelf; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"%@",strongSelf); }); };
}
使用了__strong
在strongSelf
變數作用域結束之前,對weakSelf
有一個引用,防止對象(self)提前被釋放。而作用域一過,strongSelf
不存在了,對象(self)也會被釋放。
前面的寫法雖然嚴謹了,也解決了問題了,但是作為喜歡偷懶的程式猿,會不會覺得很啰嗦?每次都要寫那兩條長長的__weak
和__strong
,而且在block里用到的self的全部要改成strongSelf,假設把一段很多self的代碼拷貝到block里,一個個改成strongSelf是不是很蛋疼?
只要在block外用了@weakify(self);然後再block里寫@strongify(self);就可以了,@strongify(self);語句後的的self可以原封不動,好像很神奇,下麵一起看看@weakify、@strongify 這兩個神奇的巨集最終替換了什麼東西。
導入RAC的頭文件,把上面的測試代碼替換成RAC中用的@weakify(self);和@strongify(self), 分屏顯示Xcode,讓右側的顯示內容改為 preprocess“,就可以看到巨集最終替換的結果。
再比如:
@weakify(self); _topView.block = ^(NSInteger tag) { @strongify(self); CGPoint point = CGPointMake(tag * SCREEN_WIDTH, self.scrollView.contentOffset.y); [self.scrollView setContentOffset:point animated:YES]; };