看下面一道Block的面试题:
int i = 10; void(^myBlock)() = ^{ NSLog(@"%d",i); }; i = 100; myBlock();
经过这个过程后,输出的i应该是10而不是100,在定义block时会将block前面的局部变量进行拷贝,后续的变量改变不会影响block内部的拷贝变量值,如果要操作block中变量的值,应该加上__block关键字。
另外一道:
Tip:如果在block中使用了self,block会对self强引用。
@property (nonatomic, strong) NSMutableArray *myBlocks; int(^sum)(int,int) = ^(int x, int y){ return [self sum:x y:y]; } [self.myBlocks addObject:sum];
注意到self对myBlocks是强引用,如果把sum加入到myBlocks数组中,myBlocks数组又会有强指针指向sum,由于sum这个block需要调用self的方法,因此sum对self是强引用,因此构成了循环引用,无法释放。
第三道:
如果self对象持有操作对象(例如类直接有block),而操作对象(如block)又直接访问了self,则block会对self构成强引用,self又对block强引用,会造成循环引用。
单纯在操作对象(如block)中操作self不会造成循环引用。
例如使用线程创建block,由于非主线程默认没有消息循环(Run Loop),因此线程销毁时block也会销毁,block为线程所有,不是self所有,不会造成循环引用。
@interface DemoObj () @property (nonatomic, strong) NSOperationQueue *queue; @end @implementation DemoObj - (instancetype)init{ if(self = [super init]){ self.queue = [[NSOperationQueue alloc] init]; } return self; } - (void)dealloc{ NSLog(@"dealloc successfully"); } - (void)demoOp:(id)obj{ NSLog(@"%@ %@",[NSThread currentThread],obj); } - (void)demoBlockOp{ [self.queue addOperationWithBlock:^{ [self demoOp:@"hello"]; }]; }这种情况下,self对queue强引用,queue对block强引用,虽然block对self也有强引用,但是线程消失时block会销毁,也就不存在引用环了,因此self只有直接拥有block时才会造成循环引用。
Tip:在这种情况下,不能使用self的弱引用(__weak Demoobj *weakself = self),这样对象会在创建时的强指针销毁时被销毁,也就是说block指向的self类不能保证其存在,故block会无法调用self,注意不能使用弱引用!!!