__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];
};

results matching ""

    No results matching ""