__block 关键字
在一个block 里头如果使用了在block 之外的变数,会将这份变数先复制一份再使用,也就是说,在没有特别宣告的状况下,对我们目前所在的block 来说,所有外部的变数都是唯读,只能读取,不能变更。至于block 里头用到的Objective-C 物件,则都会被多retain 一次。
如果我们想要让某个block 可以改动某个外部的变数,我们就要在这个需要可以被block 改动的变数前面,加上__block 关键字。
像这样是不合法的程序:
int i = 1;
void (^block)(void) = ^{
i = i + 1;
};
应该写成这样:
__block int i = 1;
void (^block)(void) = ^{
i = i + 1;
};
__weak 关键字
在使用了block 之后,内存管理会变得非常复杂,所以最好是在开启了ARC 自动内存管理之后再使用block。不过,即使开启了ARC,还是可能会遇到循环retain 的问题。
由于block 中用到的Objective-C 实例都会被多retain 一次,这边所指的Objective-C 物件也包含self,所以,假使有个实例的property 是一个block,而这个block 里头又用到了self,就会遇到循环retain 而无法释放记忆体的问题:self 要被释放才会去释放这个property,但是这个property 作为block 又retain 了self 导致self 无法被释放。
下面这段code 就有循环retain 的问题:
@interface MyClass : NSObject
- (void)doSomthing;
@property (copy, nonatomic) void (^myBlock)(void);
@end
@implementation MyClass
- (instancetype)init
{
self = [super init];
if (self) {
self.myBlock = ^ {
[self doSomthing];
};
}
return self;
}
- (void)doSomthing
{
}
@end
如果我们不想让self 被myBlock 给retain 起来,我们就要把self 变成weak reference 再传入到block 中。像是改成这样:
__weak MyClass *weakSelf = self;
self.myBlock = ^ {
[weakSelf doSomthing];
};