iOS DeveloperiOS 开发

__block关键字的实现原理

2016-09-02  本文已影响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所以地址改变。

上一篇下一篇

猜你喜欢

热点阅读