美文网首页iOS DeveloperiOS 开发
__block关键字的实现原理

__block关键字的实现原理

作者: 无边小猪 | 来源:发表于2016-09-02 17:58 被阅读0次

    __block加与不加的区别简单来说就是不加的时候做赋值操作,加了之后传地址。
    因此如果不加,block中的变量和block外的局部变量地址不同。
    如果加block中的变量和block外的局部变量地址相同。
    例如:

    {
        int a=0;
        void (^function)()=^(){
            NSLog(@"%d",a);
        };
        a = 20;
        function();
     }
    

    打印:
    2016-08-08 19:56:32.365 test[65147:434644] 0
    加了__block之后

    {
        __block int a=0;
        void (^function)()=^(){
            NSLog(@"%d",a);
        };
        a = 20;
        function();
    }
    

    打印:
    2016-08-08 19:57:03.094 test[65224:435626] 20

    这里主要想说明下__block的实现原理,先来看两段代码:
    例子1

    -(void)testBlock
    {
        __block int a=0;
        NSLog(@"a address %p",&a);
        void (^function)()=^(){
            NSLog(@"a address %p",&a);
            a = 100;
            NSLog(@"1 %d",a);
        };
        a = 20;
        function();
        NSLog(@"a address %p",&a);
        NSLog(@"2 %d",a);
        
    }
    

    输出:
    2016-08-08 19:09:19.988 test[59876:394725] a address 0xbfffc1f8
    2016-08-08 19:09:19.988 test[59876:394725] a address 0xbfffc1f8
    2016-08-08 19:09:19.989 test[59876:394725] 1 100
    2016-08-08 19:09:19.989 test[59876:394725] a address 0xbfffc1f8
    2016-08-08 19:09:19.989 test[59876:394725] 2 100

    例子2

    -(void)testBlock
    {
        
        testClass *tctemp =  [[testClass alloc] init];
        self.tc = tctemp;
        [tctemp release];
        __block int a=0;
        NSLog(@"a address %p",&a);
        void (^function)()=^(){
            NSLog(@"a address %p",&a);
            a = 100;
            NSLog(@"1 %d",a);
        };
        a = 20;
        function();
        self.tc.fun = function;
        self.tc.fun();
        NSLog(@"2 %d",a);
        NSLog(@"a address %p",&a);
    }
    

    输出:
    2016-08-08 19:13:59.914 test[60525:400152] a address 0xbff611f0
    2016-08-08 19:13:59.915 test[60525:400152] a address 0xbff611f0
    2016-08-08 19:13:59.915 test[60525:400152] 1 100
    2016-08-08 19:13:59.915 test[60525:400152] a address 0x7cb31820
    2016-08-08 19:13:59.916 test[60525:400152] 1 100
    2016-08-08 19:13:59.916 test[60525:400152] 2 100
    2016-08-08 19:13:59.916 test[60525:400152] a address 0x7cb31820
    两代代码很相似 唯一的区别是后一段代码将function赋值给了一个成员变量,而这段代码之后地址就发生了变化。

    原理:
    __block变量编译之后为一个结构:

    struct __Block_byref_val_0 {
    void *__isa;
    __Block_byref_val_0 *__forwarding;
    int __flags;
    int __size;
    NSInteger a;
    };
    

    __Block_byref_val_0 *__forwarding;指向自己。如图:


    self.tc.fun = function;语句执行完毕后,原本在栈上的__Block_byref_val_0被拷贝了一份到堆上,因为栈上的随时可能被释放。
    而内存中堆和栈上的关系如下:



    如此无论访问的是栈里的__block还是堆里的__block都是以val->__forwarding的形式访问,因此访问的都是堆上的__block所以地址改变。

    相关文章

      网友评论

        本文标题:__block关键字的实现原理

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