在使用block时要注意两点:
- block默认会拷贝局部变量的值,即所谓的闭包。
- block被某对象强引用,此时在block中使用这个对象,默认block会强引用这个对象。这时就产生了循环引用问题。
1. block默认会拷贝局部变量的值
(1)block默认会拷贝局部变量的值,block中的局部变量不可修改。
eg:代码1
//代码1- (void)testMethod { int anInteger = 42; void (^testBlock)(void) = ^{ NSLog(@"Integer is: %i", anInteger); }; anInteger = 84; testBlock(); //输出: Integer is: 42}复制代码
在block外声明局部变量并赋值, 在声明
block
时会copy局部变量当前的值(在此例中是anInteger的值始终是42)且不可修改。 此时block
中的anInteger
和block
外的anInteger
不是同一个值(他两个的内存地址是不一样的)。所以就出现了上面的情况,anInteger = 84
只是修改了block
外的局部变量,它不会影响block
里面的anInteger
。同时block
中的anInteger
是不能被修改的。
(2)当某局部变量使用 __block 进行修饰时,此局部变量在block
中不会产生copy。
eg: 代码2
//代码2 __block int anInteger = 42; void (^testBlock)(void) = ^{ NSLog(@"Integer is: %i", anInteger); }; anInteger = 84; testBlock(); //输出: Integer is: 84 //在block中也可以修改原来的值 __block int anInteger = 42; void (^testBlock)(void) = ^{ NSLog(@"Integer is: %i", anInteger); anInteger = 100; }; testBlock(); NSLog(@"Value of original variable is now: %i", anInteger); //输出: Integer is: 42 Value of original variable is now: 100复制代码
(3)当局部变量是指针类型时,你可以在block中使用这个局部变量,并修改指针所指的对象的内容。
eg:代码3
//代码3 NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@"a",@"b",@"abc",nil]; NSMutableArray *mArrayCount = [NSMutableArray arrayWithCapacity:1]; [mArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock: ^(id obj,NSUInteger idx, BOOL *stop){ [mArrayCount addObject:[NSNumber numberWithInt:[obj length]]]; }]; NSLog(@"%@",mArrayCount); // 1,1,3复制代码
代码3中与代码1的结论并不冲突。带代码3中
block
中的mArrayCount
确实是copy来的(与block
外的mArrayCount
在不同的内存空间,但是所指向的内存地址却是相同的。在block中改变的只是所指对象的内容。如果你在block中执行mArrayCount=nil;
,这才是修改局部变量的值。那么此时编译器会报错,因为违背了代码1.
2.使用__weak避免循环引用
如果一个对象强引用一个block, 然后在block中引用这个对象或者引用这个对象的属性, 此时block会强引用这个对象。 此时出现循环引用问题,造成内存泄露。__weak就是解决这个问题的。使用__weak 标记的引用是弱引用。此时在block中使用这个弱引用,block弱引用这个对象就不会产生循环引用的问题。 eg: 代码4
//代码4@property (nonatomic,copy)void (^block)(void);@property (nonatomic,copy)NSString *name;- (void)testMethod { __weak typeof(self) weakSelf = self; _block = ^{ weakSelf.name = @"hello world"; //此时不会产生循环引用问题 NSLog(weakSelf.name); }; _block();}复制代码
此时有个问题没有解决.当在block 代码执行时self有可能会销毁成为nil, 如何解决确保block在执行时self不会被销毁那?那就使用代码5:
//代码5 __weak typeof(self) weakSelf = self; _block = ^{ __strong typeof(weakSelf) strongSelf = weakSelf; //就这一句,搞定 //这一句很重要,没有的话可能会崩溃的。 if(strongSelf==nil){ return;} strongSelf.name = @"hello world"; };复制代码