美文网首页
iOS 之 Block 原理

iOS 之 Block 原理

作者: 孙伟胜 | 来源:发表于2020-11-01 15:22 被阅读0次

    Q:什么是Block?
    A:Block是将函数及其执行上下文封装起来的对象

    block的三种存储状态:

    NSGlobalBlock 在静态存储区,生存周期长,对其release或者copy retain没有用。是计算机管理的空间,程序退出就释放空间。

    NSStackBlock 在栈上,对其进行retain 或者release无效,栈上空间是计算机自动释放的,copy后会拷贝到堆空间,下来就是nsmallocBlock。

    NSMallocBlock 是堆上空间,对其retain,release,copy都有用,但是其引用计数器都是1,打印不会变。

    Block 关键字使用
    使用弱引用会带来另一个问题,weakSelf 有可能会为 nil,如果多次调用 weakSelf 的方法,有可能在 block 执行过程中 weakSelf 变为 nil。因此需要在 block 中将 weakSelf “强化“

    __weak __typeof__(self) weakSelf = self;
    NSBlockOperation *op = [[[NSBlockOperation alloc] init] autorelease];
    [ op addExecutionBlock:^ {
        __strong __typeof__(self) strongSelf = weakSelf;
        [strongSelf doSomething];
        [strongSelf doMoreThing];
    } ];
    [someOperationQueue addOperation:op];
    

    __strong 这一句在执行的时候,如果 WeakSelf 还没有变成 nil,那么就会 retain self,让 self 在 block 执行期间不会变为 nil。这样上面的 doSomething 和 doMoreThing 要么全执行成功,要么全失败,不会出现一个成功一个失败,即执行到中间 self 变成 nil 的情况。

    Block的使用

    Block与外界变量
    (1)默认情况
    对于 block 外的变量引用,block 默认是将其复制到其数据结构中来实现访问的。也就是说block的自动变量截获只针对block内部使用的自动变量, 不使用则不截获, 因为截获的自动变量会存储于block的结构体内部, 会导致block体积变大。

    block只能访问不能修改局部变量的值。

    int age = 10;
    myBlock block = ^{
        NSLog(@"age = %d", age);
    };
    age = 18;
    block(); //输出 10
    

    (2) __block 修饰的外部变量

    对于用 __block 修饰的外部变量引用,block 是复制其引用地址来实现访问的

    __block int age = 10;
    myBlock block = ^{
        NSLog(@"age = %d", age);
    };
    age = 18;
    block(); //输出18
    

    2、__block 修饰的外部变量的值就可以被block修改
    我们使用 clang 将 OC 代码转换为 C++ 文件:

    clang -rewrite-objc 源代码文件名
    
    __block int val = 10;
    转换成
    __Block_byref_val_0 val = {
        0,
        &val,
        0,
        sizeof(__Block_byref_val_0),
        10
    };
    

    会发现一个局部变量加上__block修饰符后竟然跟block一样变成了一个__Block_byref_val_0结构体类型的自动变量实例。
    此时我们在block内部访问val变量则需要通过一个叫__forwarding的成员变量来间接访问val变量。

    block的循环引用
    参考链接

    如下代码不需要使用__block,因为是对数组的操作而不是数组的赋值。浅谈Block 尾部有Block注意事项题目

    NSMutableArray *arrM = [NSMutableArray array];
        void (^testBlock)(void) = ^{
            [arrM addObject:@"addObj"];
        };
        testBlock();
    

    相关文章

      网友评论

          本文标题:iOS 之 Block 原理

          本文链接:https://www.haomeiwen.com/subject/bmziyhtx.html