1、循环引用原理
B对象是A对象的属性,若对A发送release消息,致使A引用计数为0,则会dealloc A对象,而在A的dealloc的同时,会向B对象发送release消息,这就是问题的所在。若A和B互相强引用,必然会导致A、B对象循环引用导致无法释放。
2、循环引用情景汇总:
-
delegate
-
NSTimer对于
target:self
的强引用处理。 -
block在copy时都会对block内部用到的对象进行强引用(ARC)。这种循环引用会被编译器捕捉到并及时提醒。
self.someBlock = ^(Type var){ [self dosomething]; //或者self.otherVar = XXX; //或者_otherVar = ... }; /* 外部的weakSelf是为了打破环,从而使得没有循环引用, * 而内部的strongSelf仅仅是个局部变量,存在栈中, * 会在block执行结束后回收,不会再造成循环引用。 */ @property (nonatomic, copy) dispatch_block_t block; __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); }); };
-
#define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object; #define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
@weakify(self)声明了一个指向self的弱引用类型的变量self_weak_。
@strongify(self)是声明一个_strong类型的指向self_weak的self变量
关于block使用注意:
-
跨对象的Block定义。如UITableViewCell通过block与vc进行数据通信交互,需要格外的注意。通过这样的方式如果没有处理好,block会重复的定义,且导致消息回调混乱,快速滚动会导致问题。
//在block同样会对self强引用,需要weak处理。 self.weakParent.copyBlock = ^() { self.name = @"~~~"; };
3、如何检测?
-
xcode 7.x以上编译器会出现警告
block-leak.png -
Instruments -> Leaks -> Cycles&Roots
-
工具:FBRetainCycleDetector 、 FBAllocationTracker 、 FBMemoryProfiler
iOS开发内存优化之自动检测内存泄露,检查是否有循环引用,检查内存为何如此大,Block循环引用的检查
网友评论