block循环引用原理
在block中调用self就回造成循环引用?当然不是。要创造出一个循环引用的block需要两个条件:
1、在block中引用了self
2、对block做了copy操作
例如:
@interface testClass : NSObject
@property(nonatomic,copy) Fun fun;
@end
......
-(void)testBlock
{
testClass *tctemp = [[testClass alloc] init];
self.tc = tctemp;
[tctemp release];
NSLog(@"a count %d",self.retainCount);
void (^function)()=^(){
self.name = @"hello";
};
function();
NSLog(@"a count %d",self.retainCount);
}
打印结果:
2016-09-27 10:03:58.131 test[4085:29450] a count 4
2016-09-27 10:03:58.132 test[4085:29450] a count 4
释放self所在类时dealloc并未被调用
若代码略做修改
@interface testClass : NSObject
@property(nonatomic,copy) Fun fun;
@end
......
-(void)testBlock
{
testClass *tctemp = [[testClass alloc] init];
self.tc = tctemp;
[tctemp release];
NSLog(@"a count %d",self.retainCount);
void (^function)()=^(){
self.name = @"hello";
};
self.tc.fun = function;
self.tc.fun();
NSLog(@"a count %d",self.retainCount);
}
打印结果:
2016-09-27 10:06:32.456 test[4350:31404] a count 4
2016-09-27 10:06:32.459 test[4350:31404] a count 5
释放self所在类时dealloc被调用
从上述两段代码可以看出,若仅在block中调用self是并不足以导致循环引用的,而真正导致循环引用的是copy的执行,copy执行后self引用计数器加1,self被block强引用,造成循环引用问题。
而解决该问题的方式是在MRC下定义:
__block typeof(self) weakself =self;
在ARC下定义:
__weak typeof(self) weakself =self;
在block循环引用的解决办法中weak-strong dance是比较特别的一个,该方法可以通过在执行block过程中持有self,block执行结束后释放block来解决一些问题。
用法如下:
NSLog(@"self:%ld", CFGetRetainCount((__bridge CFTypeRef)self));
__weak typeof(self) weakSelf = self;
NSLog(@"self:%ld", CFGetRetainCount((__bridge CFTypeRef)self)); void (^hellofun)()= ^{
typeof(weakSelf) strongSelf = weakSelf;
strongSelf;
NSLog(@"self:%ld", CFGetRetainCount((__bridge CFTypeRef)strongSelf));
};
hellofun();
NSLog(@"self:%ld", CFGetRetainCount((__bridge CFTypeRef)self));
打印结果如下:
2016-09-27 11:37:32.900 arctest[1128:943736] self:3
2016-09-27 11:37:32.900 arctest[1128:943736] self:3
2016-09-27 11:37:32.900 arctest[1128:943736] self:4
2016-09-27 11:37:32.900 arctest[1128:943736] self:3
上述打印结果中可以看出在hellfun()执行过程中短暂的强引用了self,而当hellofun()执行结束后,局部变量strongSelf被释放,引用计数减1,不再强引用self。
此种方法可避免在block执行的过程中self被释放而引发的异常。如果block执行过程中self的释放将被推迟到block执行结束后。