美文网首页
iOS Block学习笔记(二) -- Block截获与修改自动

iOS Block学习笔记(二) -- Block截获与修改自动

作者: brownfeng | 来源:发表于2018-11-03 00:01 被阅读73次

    Block捕获自动变量的值

    Block匿名函数又称为带自动变量值的匿名函数, 前面我们已经知道了匿名函数, 而带自动变量值如何理解?

    我们知道函数中可以可能使用的变量如下:

    1. 自动变量(局部变量)
    2. 函数的参数
    3. 静态局部变量
    4. 静态全局变量
    5. 全局变量
    

    而在函数的多次执行过程中, 能够传递的变量有:

    1. 静态局部变量
    2. 静态全局变量
    3. 全局变量
    

    通常情况下,我们在OC/C++中可以保持变量值且使用类对象来保持变量,并且能够多次持有该变量.

    然而,Blocks提供了这种类似于类的保存变量值的方式,并且能够多次持有该变量. 因此使用Block可以不用声明类也无需使用全局变量/静态变量,就能够满足这种条件.

    如下代码可以证明:

    int main() {
        int dmy = 256;
        int val = 10;
        const char *fmt = "val = %d\n";
        void (^blk)(void) = ^ {printf(fmt, val);};
    
        val = 2;
        fmt = "These values were changed. val = %d\n";
    
        blk();
    
        return 0;
    }
    

    最后结果运行结果答应: val = 10.

    表示Block中可以截获所使用的自动变量的值, 即保存自动变量在创建Block的瞬时值. 因为Block保存的是瞬时值, 在执行Block语法以后,即使修改了自动变量的值,也不会影响Block中捕获的自动变量在Block运行时候的值.

    __block变量修饰符

    前面,我们了解到Block能在执行创建Block语法时,自动变量的瞬时值. 但是一旦截获该瞬时值, 在Block代码中是无法修改的, 编译器会报错.

    int val = 0;
    void (^blk)(void) = ^{ val = 1;}; // 编译时,这里就会报错.
    

    但是如果被截获的自动变量是OC类对象,也是无法修改该对象的值, 但是能够操作该对象的成员变量.

    id array = [[NSMutableArray alloc] init];
    void (^blk)(void) = ^{ 
        [array appendObject:@(1)];// 不会报错,可以正常运行
        array = [[NSMutableArray alloc] init]; // 会报错, 无法修改自动变量的值
    };
    

    OC提供__block修饰符,用于修饰自动变量,此时我们就能在Block语法中修改被截获的自动变量值.

    __block int val = 0;
    void (^blk)(void) = ^{ val = 1;};// 因为val是__block修饰,因此可以修改
    blk();
    printf("val = %d\n", val);
    

    该源码执行的结果是: val = 1. 对于对象类型的变量,也能使用__block进行修饰

    __block id array = [[NSMutableArray alloc] init];
    void (^blk)(void) = ^{ 
        [array appendObject:@(1)];// 不会报错,可以正常运行
        array = [[NSMutableArray alloc] init]; // 不会报错, 可以修改__block自动变量的值
    };
    blk();
    

    注意Block并没有实现对C预言数组的截获:

    const char text[] = "hello";
    void (^blk)(void) = ^ {
        printf("%c\n", text[2]); //这里会出错, 因为Block并没有实现对C预言数组的截获
    }
    

    我们一般使用指针来规避该问题:

    const char *text = "hello";
    void (^blk)(void) = ^ {
        printf("%c\n", text[2]); //Block可以截获指针变量(但是无法截获C语言数组变量)
    }
    

    参考资料

    1. <<Objective-C 高级编程: iOS与OSX多线程和内存管理>>

    相关文章

      网友评论

          本文标题:iOS Block学习笔记(二) -- Block截获与修改自动

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