返回

__block变量和对象的完美兼容解读

IOS

__block变量和对象的兼容性

在之前的文章[iOS]Block系列探究二 - 捕获变量中,我们讨论过__block是如何处理基础类型的局部变量使block内部可以修改局部变量的。这篇文章我们仔细研究下__block说明符修饰变量和对象。

首先我们研究一下__block说明符修饰局部变量。不多说,直接上OC代码:

int main(int argc, const char * argv[]) {
    __block int num = 10;
    
    void (^block)(void) = ^{
        num++;
        printf("num = %d\n", num);
    };
    
    block();
    
    return 0;
}

运行结果:

num = 11

从结果可以看出,block内部可以修改局部变量num的值。这是因为__block说明符告诉编译器,这个局部变量可能被block捕获,编译器会为这个局部变量分配一块内存,这个内存的地址不会随着block的执行而改变,这样block内部就可以通过这个地址来修改局部变量的值。

接下来我们研究一下__block说明符修饰对象。我们还是上代码:

int main(int argc, const char * argv[]) {
    __block NSString *str = @"hello";
    
    void (^block)(void) = ^{
        str = @"world";
        printf("str = %@\n", str);
    };
    
    block();
    
    return 0;
}

运行结果:

str = world

从结果可以看出,block内部也可以修改对象str的值。这是因为__block说明符告诉编译器,这个对象可能被block捕获,编译器会为这个对象分配一块内存,这个内存的地址不会随着block的执行而改变,这样block内部就可以通过这个地址来修改对象的值。

需要注意的是,__block说明符只能修饰局部变量和对象,不能修饰全局变量和静态变量。这是因为全局变量和静态变量的地址是固定的,不会随着block的执行而改变,因此不需要使用__block说明符来告诉编译器。

__block变量和对象的内存管理

__block变量和对象的内存管理与普通变量和对象有所不同。普通变量和对象在block执行结束后,其内存会被自动释放。而__block变量和对象的内存不会被自动释放,需要手动释放。这是因为__block变量和对象被block捕获,block执行结束后,这些变量和对象仍然存在于内存中。如果我们不手动释放这些变量和对象的内存,就会造成内存泄漏。

__block变量和对象的内存释放方式与普通变量和对象相同,可以使用release方法来释放内存。例如:

__block NSString *str = @"hello";

void (^block)(void) = ^{
    str = @"world";
    printf("str = %@\n", str);
};

block();

[str release];

在block执行结束后,我们使用[str release]方法来释放str对象的内存。

总结

__block变量和对象可以被block捕获,block内部可以修改这些变量和对象的值。__block变量和对象的内存管理与普通变量和对象有所不同,需要手动释放内存。