Block(global, stack, malloc)

大神博客链接

自己测试的数据:
测试时在buildSetting中将ARC关掉,因为在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上。

    /****** __NSGlobalBlock__ (没有访问auto变量)******/

    // 什么参数也不引用
    NSLog(@"%@",^{NSLog(@"*******");} );
    
    // 引用全局变量或者全局静态变量
    NSLog(@"%@", ^{NSLog(@"%d, %d", a, global_i);});
    
    // 引用局部静态变量
    NSLog(@"%@", ^{NSLog(@"%d", static_local_k);});
    
    // 被强指针引用,并且只引用了全局变量或静态变量
    strongBlock = ^{NSLog(@"%d", a);};
    NSLog(@"%@", strongBlock);

    /******__NSStackBlock (访问了auto变量)******/

    // 只引用局部变量
    NSLog(@"%@", ^{NSLog(@"%d%d%d", a, static_local_k, static_global_j);});
    // 引用局部变量和全局变量(或静态变量)
    NSLog(@"%@", ^{NSLog(@"%d, %d", a, global_i);});
    
    
    /****** __NSMallocBlock (__NSStackBlock 执行copy操作)******/

    // 被强指针引用,并且引用了局部非静态变量
    strongBlock = ^{NSLog(@"%d%d", a, global_i);};
    NSLog(@"%@", strongBlock);
    
    // 被强指针引用,并且引用了局部非静态变量,和全局变量(或静态)
    strongBlock = ^{NSLog(@"%d%d", a, global_i);};
    NSLog(@"%@", strongBlock);

总结:

NSGlobalBlock(不持有对象)

  1. block无论是否被strong类型的属性持有,只要不引用任何变量,要么这个block就是__NSGlobalBlock
  2. block无论是否被strong类型的属性持有,只引用全局变量或者静态变量,要么这个block就是__NSGlobalBlock

NSStackBlock(不持有对象)

  1. 不被strong类型的属性所持有,并且要引入局部变量,那么这个block就是__NSStackBlock (只要引入局部变量,有没有全局或者静态都一样)

NSMallocBlock(持有对象)

  1. strong类型的属性所持有,并且引用了局部变量,那么这个block就是__NSMallocBlock (只要引入局部变量,有没有全局或者静态都一样)

Block的副本:

Block的类 副本源的配置存储域 复制效果
__NSConcreteStackBlock 从栈复制到堆
__NSConcreteGlobalBlock 程序的数据区(全局区) 什么也不做
__NSConcreteMallocBlock 引用计数增加

不管block配置在何处,用copy方法复制都不会引起任何问题。在不确定时调用copy方法即可。(浪费CPU资源)

__block变量

Block被复制到堆上时,__block变量也被复制到堆上,被Block持有。
__block变量同时被两个Block持有时,会增加__block的引用计数。

__block变量结构体中__forwarding指针的作用

先给个结论:
__forwarding指向__block变量本身。当__block变量在栈上的时候,__forwarding指向__block在栈上的地址;当__block被复制到堆上后,栈上__block变量的__forwarding指向__block在堆上的地址,同样,堆上__block变量的__forwarding指针也指向它在堆上的地址,这样,当在函数中改变__block变量时,访问的便是同一个__block变量。细节看下面代码。

    typedef void (^blk_t)(void);
    
    __block int val = 0;
    
    
    blk_t blk = [^{++val;} copy];    // 可转化为++(val.__forwarding->val)
    
    ++val;     // 可转化为++(val.__forwarding->val)
    
    blk();
    NSLog(@"val:%d", val);

上述代码执行后val的值变为2


Screen Shot 2018-03-19 at 14.25.35.png

你可能感兴趣的:(Block(global, stack, malloc))