block 内部修改值

在使用 block 的时候想修改外部的值,一般都是需要时用 __block 修饰才能修改,但是有一个些“可变集合类”属于例外和一些例外情况。

第一种情况 __block修饰非集合类
        __block NSInteger number = 1;        
        Block block = ^(NSInteger a) {
                        
            number += a;
            
            return number;
        };
        
        NSInteger b = block(5);
        
        NSLog(@"b=%ld", b);
        
复制代码

输出的结果是

2017-04-20 09:33:24.709179+0800 Block[24319:2750379] b=6
复制代码
第二种情况 没有__block修饰的可变集合类
        NSMutableArray *array1 = [NSMutableArray new];
        [array1 addObject:@0];
        
        Block block = ^(NSInteger a) {
            
            [array1 addObject:@1];
                        
            return a;
        };
        
        NSInteger b = block(5);
        NSLog(@"b=%ld", b);
        
        NSLog(@"array=%@", array1);
复制代码

输出的结果是

2017-04-20 09:33:24.709179+0800 Block[24319:2750379] b=5
2017-04-20 09:33:24.709399+0800 Block[24319:2750379] array=(
0,
1
)
复制代码
第三种情况 __block修饰的可变集合类
        __block NSMutableArray *array1 = [NSMutableArray new];
        [array1 addObject:@0];
        
        Block block = ^(NSInteger a) {
            
            [array1 addObject:@1];
            NSMutableArray *array2 = [NSMutableArray arrayWithObject:@2];
            array1 = array2;
            return a;
        };
        
        NSInteger b = block(5);
        NSLog(@"b=%ld", b);
        
        NSLog(@"array=%@", array1);
复制代码

输出的结果是

2017-04-20 09:33:24.709179+0800 Block[24319:2750379] b=5
2017-04-20 09:33:24.709399+0800 Block[24319:2750379] array=(
2
)
复制代码
第四种情况 没有__block修饰属于当前对象属性的可变集合类
        self.array1 = [NSMutableArray new];
        [self.array1 addObject:@0];
        
        Block block = ^(NSInteger a) {
            
            [array1 addObject:@1];
            NSMutableArray *array2 = [NSMutableArray arrayWithObject:@2];
            self.array1 = array2;
            return a;
        };
        
        NSInteger b = block(5);
        NSLog(@"b=%ld", b);
        
        NSLog(@"array=%@", array1);
复制代码

输出的结果是

2017-04-20 09:33:24.709179+0800 Block[24319:2750379] b=5
2017-04-20 09:33:24.709399+0800 Block[24319:2750379] array=(
2
)
复制代码
总结

我们从上面的例子可以总结出来以下结果

  • __block 修饰的非集合、集合对象都可以赋值
  • 没有__block修饰的集合可以修改其中的对象
  • 当前类属性没有__block修饰的时候也可以赋值

如果没有使用 __block修饰会发生什么呢?

如图,系统会直接提示错误。

分析

知道结果之后,我们分析一下原因

1、为什么__block修饰之后我们可以赋值呢?

使用 clang -rewrite-objc main.m编译一下得到以下结果

  • 没有使用__block修饰数组的情况
  • 使用__block修饰数组的情况

对比之后我们可以发现(系统也给了注释)有没有 __block 的区别就是

  • 拷贝值
  • 拷贝指针
NSMutableArray *array = __cself->array1; // bound by copy

__Block_byref_array1_1 *array1 = __cself->array1;  // bound by ref
复制代码

只有拷贝指针的才能执行赋值。

2、为什么当前类属性我们可以赋值呢?

同样编译一下可得

因为 self.调用了属性的set方法,使用runtime实现消息发送,不过可能会存在内存泄露。

不用self.也可以实现赋值,

             _array1 = array2;
复制代码

编译后是

            (*(NSMutableArray **)((char *)self + OBJC_IVAR_$_Test$_array1)) = array2;
复制代码
3、为什么没有__block的可变集合类我们可以修改其中的对象呢?

从 1 的第一张图我们可以看到 [array1 addObject:@1];编译之后的是

            ((void (*)(id, SEL, ObjectType))(void *)objc_msgSend)((id)array1, sel_registerName("addObject:"), (id)((NSNumber *(*)(Class, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 1));
复制代码

同 2 调用的set方法,此处也是消息发送。

水平有限,如有错误还请指出~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值