問題出現(xiàn)描述
當多個對象相互持有形成一個封閉的環(huán)時,循環(huán)引用問題隨之出現(xiàn),導(dǎo)致內(nèi)存泄漏。
常見幾種循環(huán)引用總結(jié)
1、代理delegate 使用關(guān)鍵字 strong 描述
@property(nonatomic,strong)delegate;
self.operationView.delegate = self;
在這里 B強引用A,而A的delegate屬性指向B,這里的delegate是用strong修飾的,所以A也會強引用B,這是一個典型的循環(huán)引用樣例。其解決其的方式大家也都知道,即將delegate改為弱引用(weak)。
2、block與環(huán)
self.block = ^{
self.count =2;
};
在這里 self持有block,而堆上的block又會持有self,所以會導(dǎo)致循環(huán)引用,解決這種循環(huán)引用的常用方式如下(這種解決方式可以解決大部分block引起的循環(huán)引用):
__weak typeof(self) weakSelf = self;
self.block = ^{
weakSelf.count =2;
};
特備注:有時候直接使用 weakSelf 會導(dǎo)致內(nèi)存提前回收,導(dǎo)致出現(xiàn)錯誤,如下:
@interface UIviewController ()
@property (nonatomic, copy) dispatch_block_t block;
@property (nonatomic, strong) NSString *str;
@end
@implementation UIviewController
- (void)dealloc {
}
- (void)viewDidLoad {
[super viewDidLoad];
self.str = @"111";
__weak typeof(self) weakSelf = self;
self.block = ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@", strongSelf.str);
});
};
self.block();
}
這里會有兩種情況:
從 一個VC push到 上面的VC,10s之內(nèi)沒有pop的話,block會執(zhí)行打印出來111。
從一個VC push到 上面的VC,10s之內(nèi)pop的話 ,上面的VC會立即執(zhí)行dealloc,從而導(dǎo)致block打印出(null)。這種情況就是使用weakSelf的缺陷,可能會導(dǎo)致內(nèi)存提前回收。
解決辦法:
@interface UIviewController ()
@property (nonatomic, copy) dispatch_block_t block;
@property (nonatomic, strong) NSString *str;
@end
@implementation UIviewController
- (void)dealloc {
}
- (void)viewDidLoad {
[super viewDidLoad];
self.str = @"111";
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(self) strongSelf = weakSelf;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@", strongSelf.str);
});
};
self.block();
}
這么做和直接用self有什么區(qū)別,為什么不會有循環(huán)引用:外部的weakSelf是為了打破環(huán),從而使得沒有循環(huán)引用,而內(nèi)部的strongSelf僅僅是個局部變量,存在棧中,會在block執(zhí)行結(jié)束后回收,不會再造成循環(huán)引用。
這么做和使用weakSelf有什么區(qū)別:唯一的區(qū)別就是多了一個strongSelf,而這里的strongSelf會使ClassB的對象引用計數(shù)+1,使得ClassB pop到A的時候,并不會執(zhí)行dealloc,因為引用計數(shù)還不為0,strongSelf仍持有ClassB,而在block執(zhí)行完,局部的strongSelf才會回收,此時ClassB dealloc。