在使用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";
};