__block的一些思索总结

参考链接 https://www.jianshu.com/p/ee9756f3d5f6

命令: -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 ViewController.m

1. 常量

- (void)test1 {
    
    __block int a = 1;
    int b = 2;
    NSLog(@"1a----%p   %d",&a,a);
    NSLog(@"1b----%p   %d",&b,b);

    self.blockkk = ^(void){
        
        NSLog(@"block 2a----%p   %d",&a,a);
        NSLog(@"block 2b----%p   %d",&b,b);
    };
    
    NSLog(@"3a----%p   %d",&a,a);
    NSLog(@"3b----%p   %d",&b,b);
    
    b = 89757;
    a = 89758;
    
    self.blockkk();
    
    NSLog(@"4a----%p   %d",&a,a);
    NSLog(@"4b----%p   %d",&b,b);
}

输出为

 __block[68513:7304153] 1a----0x7ffee5b45448   1
 __block[68513:7304153] 1b----0x7ffee5b4542c   2
 __block[68513:7304153] 3a----0x604000226558   1
 __block[68513:7304153] 3b----0x7ffee5b4542c   2
 __block[68513:7304153] block 2a----0x604000226558   89758
 __block[68513:7304153] block 2b----0x60400044d378   2
 __block[68513:7304153] 4a----0x604000226558   89758
 __block[68513:7304153] 4b----0x7ffee5b4542c   89757

可以很清楚的看到, 被__block修饰的在之后引用,地址已经变了 实际上,我们使用clang查看之后有可以发现实际上是这样的, a的使用已经是使用的block里面结构体的地址

    b = 89757;
    (a.__forwarding->a) = 89758;

然后,被__block修饰的 之后调用是 (a.__forwarding->a) 其实已经不是访问原地址了

2. 对象

其实对象是一样的逻辑. 但是我在打印对象使用的 %@,实在是犯了最简单的错误, 实际上使用%@是打印其中的值, 所以最好使用%p吧 哈哈 别像我一样搞半天头疼

- (void)test5
{
    __block FSPerson *blockP = [[FSPerson alloc] init];
    FSPerson *p = [[FSPerson alloc] init];
    
    NSLog(@"1--- %p --- %p",&p,&blockP);
    void (^myBlock)(void) = ^{
        
        blockP.name = @"89757";
        p.name = @"89758";
        
        NSLog(@"2--- %p --- %p",&p,&blockP);
    };
    
    NSLog(@"3--- %p --- %p",&p,&blockP);
    myBlock();
    NSLog(@"4--- %p --- %p",&p,&blockP);
}

打印为

 __block[68726:7328927] 1--- 0x7ffeea7d0418 --- 0x7ffeea7d0448
 __block[68726:7328927] 3--- 0x7ffeea7d0418 --- 0x60000025a668
 __block[68726:7328927] 2--- 0x600000252e60 --- 0x60000025a668
 __block[68726:7328927] 4--- 0x7ffeea7d0418 --- 0x60000025a668

总结

不被__block修饰的, 实际上后面在使用 还是跟前面一样地址, 而block内部实际上拷贝到了堆上 , 没有为其建立结构体 , 而且 值拷贝.
使用__block修饰的, 实际上block后面的访问都是(a.__forwarding->a) = 89758;也就是, 实际上跟之前的地址已经不同了,并且在结构体内, 给予了内存, 所以也可以对其修改.

个人认为,__block需要封装对象,肯定是消耗性能并且更加的耗时, 所以苹果给出了2中解决办法,不用__block值拷贝不可修改,使用__block的话, 就是完整复制一份, 这样可以修改.同时 这是对 block是封装了函数及其函数调用的完美解释..

    b = 89757;
    (a.__forwarding->a) = 89758;

你可能感兴趣的:(__block的一些思索总结)