IOS进阶-理解OC中block (二)

上文中介绍了闭包及block的关系,下面结合具体场景再深入探究。

应用场景

代码如下:

NSInteger globalVar = 1;
static NSInteger globalStaticVar = 1;

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here
        NSInteger var = 1;
        static NSInteger staticVar = 1;
        __block NSInteger blockVar = 1;
        NSMutableArray *arr = [NSMutableArray arrayWithArray:@[@1,@2,@3]];
        void (^block)(void) = ^(void) {
            NSLog(@"局部变量: %ld", var);
            NSLog(@"静态变量: %ld", staticVar);
            NSLog(@"全局变量: %ld", globalVar);
            NSLog(@"全局静态变量: %ld", globalStaticVar);
            NSLog(@"block修饰变量: %ld", blockVar);
            [arr addObject:@5];
            NSLog(@"数组: %@", arr);
            globalVar = 3;
        };
        
        var = 2;
        staticVar = 2;
        globalVar = 2;
        globalStaticVar = 2;
        blockVar = 2;
        [arr addObject:@4];
        arr = nil;
        
        block();
        
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
        return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

控制台打印

2021-04-21 14:01:55.859015+0800 OCPP[3452:192737] 局部变量: 1
2021-04-21 14:01:55.859754+0800 OCPP[3452:192737] 静态变量: 2
2021-04-21 14:01:55.859880+0800 OCPP[3452:192737] 全局变量: 2
2021-04-21 14:01:55.860001+0800 OCPP[3452:192737] 全局静态变量: 2
2021-04-21 14:01:55.860101+0800 OCPP[3452:192737] block修饰变量: 2
2021-04-21 14:01:55.860419+0800 OCPP[3452:192737] 数组: (
    1,
    2,
    3,
    4,
    5
)

OC文件底层编译命令: xcrun -sdk iphonesimulator clang -rewrite-objc main.m。生成.cpp 文件

NSInteger globalVar = 1;
static NSInteger globalStaticVar = 1;

struct __Block_byref_blockVar_0 {
  void *__isa;
__Block_byref_blockVar_0 *__forwarding;
 int __flags;
 int __size;
 NSInteger blockVar;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  NSInteger var;
  NSInteger *staticVar;
  NSMutableArray *arr;
  __Block_byref_blockVar_0 *blockVar; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSInteger _var, NSInteger *_staticVar, NSMutableArray *_arr, __Block_byref_blockVar_0 *_blockVar, int flags=0) : var(_var), staticVar(_staticVar), arr(_arr), blockVar(_blockVar->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

__main_block_impl_0中__block_impl我们点击去可以看到有个isa指针。所以block本质上就是个对象,一个将定义的函数以及关联的上下文封装起来的一个对象。

我们在block中引用的num,staticNum,blockNum,在这里都被定义成了内部属性.但是并没有发现globalNum和globalStaticNum

num和staticNum还是保留其原来的NSInteger类型,但是blockNum使用的是``__Block_byref_blockNum_0`类型.

结论如下:

变量类型 block处理方式
局部变量 值捕获,block块外部改变值不会对block内部产生影响
静态变量 指针捕获,block块外部改变值会对block内部产生影响
全局变量/全局静态变量 不捕获,直接取值
使用__block关键字修饰 是指针捕获,但是实现不同于静态变量,它会生成一个新的结构体对象。

block形式

block有三种形式,全局block(NSGlobalBlock),栈block(NSStackBlock),堆block(NSMallocBlock)

  • 全局block存储在初始化data区
  • 栈block存储在栈(stack)区
  • 堆block存储在堆(heap)区
    NSLog(@"%@", [^(void){
        
    } class]); // 为引用外部变量

    NSLog(@"%@", [^(void){
        NSInteger num = globalStaticNum;
    } class]); // 引用全局静态变量

    NSLog(@"%@", [^(void){
        NSInteger num = globalNum;
    } class]); // 引用全局变量

    static NSInteger temp = 1;
    NSLog(@"%@", [^(void){
        NSInteger num = temp;
    } class]); // 静态变量

    NSInteger number = 1;
    NSLog(@"%@", [^(void){
        NSInteger num = number;
    } class]); // 局部变量

    NSLog(@"%@", [^(void){
        NSInteger num = self.num;
    } class]); // 局部变量

    NSLog(@"%@", [^(void){
        NSInteger num = self.numObj;
    } class]); // 局部变量

        self.block = ^(b1)(void) {
      
    };
        NSLog(@"%@",self.block); // copy全局block

        self.block = ^(b1)(void) {
      id n = self.numObj;
    };
        NSLog(@"%@",self.block); // copy栈block
    
/*
控制台打印如下:
__NSGlobalBlock__
__NSGlobalBlock__
__NSGlobalBlock__
__NSGlobalBlock__
__NSStackBlock__
__NSStackBlock__
__NSStackBlock__
__NSGlobalBlock__
__NSMallocBlock__
*/

结论如下:

使用方式 结果
不使用外部变量 全局block
对全局block进行copy操作 全局block
使用外部变量,变量为全局变量 全局block
使用外部变量,变量非全局变量 栈block
对栈block进行copy操作 堆block
对堆block进行copy操作 不进行操作,引用计数+1

__block关键字

上文提到,使用关键字修饰的变量,在block中进行指针捕获后并没有定义成原数据类型的指针,而是生成了一个新的结构体对象__Block_byref_blockNum_0:

struct __Block_byref_blockVar_0 {
  void *__isa;
__Block_byref_blockVar_0 *__forwarding;
 int __flags;
 int __size;
 NSInteger blockVar;
};
  • 可以发现__Block_byref_blockNum_0在内部才持有了定义的变量
  • 还有一个指向同类型的指针__forwarding

关于forwarding指针:

  • forwarding是一个指向自身的指针, 当栈block发生copy操作后,会指向其拷贝的堆block。
  • 所以对block中持有的变量修改,其实修改的是最终指向的那个block。这样保证了访问的值是同样了.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容