iOS中__block底层原理是怎么样的

2019-05-08  本文已影响0人  guoguojianshu

我们都知道block是会对申明它的范围内,所有变量都可以为其捕获的。这也就是说,那个范围内的全部变量,在块里依然可用的。但是不能对捕获的变量进行修改,除非加上__block的标志才可以进行修改,这个底层是怎么回事呢?

先对基本数据类型进行查看

 int num = 10;
    
    NSLog(@"初始化时候的指针 %p",&num);
    void (^ myBlock)(void) = ^{
        NSLog(@"block中的指针%p",&num);
    };
    myBlock();
    NSLog(@"被block捕获后的指针%p",&num);

打印结果为

2019-05-08 11:02:58.925066+0800 block[58634:10234102] 初始化时候的指针 0x7ffeef5cb9ec
2019-05-08 11:02:58.925222+0800 block[58634:10234102] block中的指针0x600000396180
2019-05-08 11:02:58.925309+0800 block[58634:10234102] 被block捕获后的指针0x7ffeef5cb9ec

1.如何确定指针是在栈中,还是在堆中呢,看指针的大小,因为栈中的指针是很大的,是从高地址开始分配的,堆中的指针是从低地址开始分配的;
或者是把这些16进制的指针转为10进制,然后用大指针数减去小指针数,获得字节差,再除以两次1024,可以得到多少M的空间,因为堆地址要小于栈地址,又因为iOS中一个进程的栈区内存只有1M,Mac也只有8M,显然num已经是在堆区了。

注意:但是最后的指针又回到栈了。

 __block  int num = 10;
    
    NSLog(@"初始化时候的指针 %p",&num);
    void (^ myBlock)(void) = ^{
        NSLog(@"block中的指针%p",&num);
    };
    myBlock();
    NSLog(@"被block捕获后的指针%p",&num);

打印结果

2019-05-08 11:34:28.594960+0800 block[59001:10269363] 初始化时候的指针 0x7ffee29699e8
2019-05-08 11:34:28.595104+0800 block[59001:10269363] block中的指针0x6000001f4d38
2019-05-08 11:34:28.595193+0800 block[59001:10269363] 被block捕获后的指针0x6000001f4d38

有__block标识的,最后的指针也会在堆中,
总结:加入了__block的表示后,栈中的指针地址永久的被copy到堆中了,不加入__block时候,只是在block内部时候会被暂时的从栈中被copy到堆中,等block结束后又回到栈中了,因为block对象布局中有copy方法,所以可以进行copy操作

对对象的情况

 NSMutableString * mString = [NSMutableString stringWithString:@"xiaoli"];
    NSLog(@"初始化时候 mString指向堆中的地址%p\n mString在栈中的指针地址%p mString = %@",mString,&mString,mString);
    void(^myBlock)(void) = ^{
        mString.string = @"xiaowang";
        NSLog(@"在block中的时候 mString指向堆中的地址%p\n mString在栈中的指针地址%p mString = %@",mString,&mString,mString);

    };
    myBlock();
    NSLog(@"在block执行完之后的时候 mString指向堆中的地址%p\n mString在栈中的指针地址%p mString = %@",mString,&mString,mString);

打印结果

2019-05-08 12:02:30.881439+0800 block[59318:10294124] 初始化时候 mString指向堆中的地址0x6000004fb180
 mString在栈中的指针地址0x7ffee95b09e8 mString = xiaoli
2019-05-08 12:02:30.881615+0800 block[59318:10294124] 在block中的时候 mString指向堆中的地址0x6000004fb180
 mString在栈中的指针地址0x6000004fbfb0 mString = xiaowang
2019-05-08 12:02:30.881698+0800 block[59318:10294124] 在block执行完之后的时候 mString指向堆中的地址0x6000004fb180
 mString在栈中的指针地址0x7ffee95b09e8 mString = xiaowang

加入__block表示后

__block  NSMutableString * mString = [NSMutableString stringWithString:@"xiaoli"];
    NSLog(@"初始化时候 mString指向堆中的地址%p\n mString在栈中的指针地址%p mString = %@",mString,&mString,mString);
    void(^myBlock)(void) = ^{
        mString.string = @"xiaowang";
        NSLog(@"在block中的时候 mString指向堆中的地址%p\n mString在栈中的指针地址%p mString = %@",mString,&mString,mString);

    };
    myBlock();
    NSLog(@"在block执行完之后的时候 mString指向堆中的地址%p\n mString在栈中的指针地址%p mString = %@",mString,&mString,mString);

打印结果

2019-05-08 12:06:47.865743+0800 block[59378:10299298] 初始化时候 mString指向堆中的地址0x600002507a20
 mString在栈中的指针地址0x7ffeeae199e8 mString = xiaoli
2019-05-08 12:06:47.865886+0800 block[59378:10299298] 在block中的时候 mString指向堆中的地址0x600002507a20
 mString在栈中的指针地址0x6000025079b8 mString = xiaowang
2019-05-08 12:06:47.866087+0800 block[59378:10299298] 在block执行完之后的时候 mString指向堆中的地址0x600002507a20
 mString在栈中的指针地址0x6000025079b8 mString = xiaowang
上一篇下一篇

猜你喜欢

热点阅读