iOS多线程_03_Block

本文详细介绍了Block的概念、格式及使用方法,并通过实例演示了如何利用Block进行编程。此外,还探讨了Block在处理外部变量时的注意事项及其与__block修饰符的关系。

  1、block定义

  是准备好的一段代码片段,在需要的时候执行

  注意:block 是C语言的格式

  2、block格式

  格式:返回类型 (^blockName) (参数类型) = ^(形参列表) { 代码实现 };

  提示:如果没有参数,格式可以简化

  格式:返回类型 (^blockName) () = ^ { 代码实现 };

  在Xcode代码编辑中输入 inlineBlock,有提示,这是block格式的快捷方式

  3、示例代码

  (1)先看看block怎么用

    void (^myBlock)() = ^ {
        NSLog(@"hello block");
    };
    
    // 调用block
    myBlock();

  输出结果是:hello block

  (2)带参数

    void (^sumBlock)(int, int) = ^(int x, int y) {
        NSLog(@"%d", x + y);
    };
    
    sumBlock(10, 20);

  输出结果是:30

  (3)block到底干了什么

    int x = 10;
    NSLog(@"%p", &x);
    
    // 在定义block时,如果block中使用到外部的“局部”变量,block会建立该变量的副本(会记录当前x的数值)
    void(^myBlock)() = ^ {
        NSLog(@"%d", x);
        NSLog(@"%p", &x);
    };
    myBlock();

  输出结果:

  0xbfffc8e4

  10

  0x8e632a4

  从地址可以看出block内部的x跟外部的x不是同一个,不过内容都是10

  block的作用:在 NSLog(@"%d", x); 中,因为使用到“局部变量”x,所以myBlock会建立x的副本,在输出 NSLog(@"%d", x);的时候把x的值输出。

  所以,可以得出结论,block里面用到了谁,block就会建立谁的副本,在使用的时候输出它的值。

  4、常见面试题

  (1)在使用外部变量时,默认不允许在块代码中直接修改外部变量的数值

  上边这张图很明显的说明,默认情况下是不允许在块代码中直接修改外部变量的数值的

  (2)如果要修改外部变量的值,需要在定义变量的时候用 __block 修饰

  (3)__block的另一个特点:被__block修饰的变量,在值改变的时候,块代码内会同步被改变后的值

  上面这段代码的输出结果是:

  0xbfffc8e8

  20

  === 0x8cadbb0

  20

  结果表明,在 x = 20; 之后,block内部的x值的副本也改变了

  如果把 __block 去掉,输出结果是:

  0xbfffc8e4

  10

  === 0xa275f74

  20

  注意:在x = 20;之后调用block才会同步20的值,一定不要忘了代码是顺序执行的

  提示:为了保证代码的可读性,通常不使用 __block

  总结:上面介绍的block的用法,block本质上是创建了副本,要注意的是,副本的内容还是变量的内容,而副本在内存中存储的地址变了

  (4)再来看block保存指针变量

 1     // 指针包含指针的地址,和指向的地址
 2     NSMutableString *str = [NSMutableString stringWithString:@"hello"];
 3     NSLog(@"%p %p", &str, str);
 4     
 5     void(^myBlock)() = ^ {
 6         // 修改指针指向内存空间的内容
 7         [str setString:@"world"];
 8         NSLog(@"%p %p", &str, str);
 9         NSLog(@"%@", str);
10     };
11     
12     myBlock();
13     NSLog(@"%p %p", &str, str);
14     NSLog(@"%@", str);

  输出结果是:

  0xbfffc8e4 0x8c281f0

  0x8d0b834 0x8c281f0

  world

  0xbfffc8e4 0x8c281f0

  world

这幅图并不准确,block保存的副本具体在哪儿存着,我也不是太清楚,因为从地址观察,block副本很可能不是在栈中,不过,有一点确定的是,block肯定建立了一个副本。可以将block当做特殊的对象。

  第3行代码,分别输出了栈中指针str的地址和堆中对象hello的地址。

  第5行代码,block建立了str的副本指针,内容不变,地址变了;然后第7行代码修改了block中str指向的对象的内容,因此堆中对象的内容变为world。

  第13行代码,可以说明,指针str的地址和指向的地址都没有变。

  第14行代码,输出了str指针指向的对象内容。

转载于:https://www.cnblogs.com/yudigege/p/3930408.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值