Block的三种类型

作者: 大兵布莱恩特 | 来源:发表于2019-02-22 10:40 被阅读3次

    block有3中类型,可以通过 class方法或者 isa 指针查看具体类型,最终都是继承与NSBlock 的类型 有NSGlobalBlock,NSMallocBlock,NSStackBlock
    这三种 block在内存中分配的位置是不同的

    image.png

    那么什么样的 block 是 NSGlobalBlock?什么样的 block 是 NSMallocBlock ?什么样的 block 是NSStackBlock ?

    为了能够准确的研究B lock 内存分配 一下代码是在非ARC环境下测试

    image.png

    如果 block 内部没有访问auto 变量 那么这个 block 就是 NSGlobalBlock 类型

    int height = 10; ///全局变量
    void testBlock() {
        
        ///globalBlock
        void(^block1)(void)  = ^ {
            NSLog(@"hello world");
        };
        NSLog(@"%@",[block1 class]);
        ///MallocBlock
        static int age = 10; ///静态变量
        void(^block2)(void) = ^{
            NSLog(@"age = %d",age);
        };
        NSLog(@"%@",[block2 class]);
        ///StackBlock
        NSLog(@"%@",[^{
            NSLog(@"height = %d",height);
        } class]);
        
    }
    
    控制器输出打印结果
    
    2019-02-22 10:11:20.325501+0800 Block01[18811:1127199] __NSGlobalBlock__
    2019-02-22 10:11:20.325704+0800 Block01[18811:1127199] __NSGlobalBlock__
    2019-02-22 10:11:20.325716+0800 Block01[18811:1127199] __NSGlobalBlock__
    
    

    如果 block 内部访问了 auto 变量 那么这个 block 就是 NSStackBlock

    int height = 10; ///全局变量
    void testBlock() {
        
        ///__NSGlobalBlock__
        void(^block1)(void)  = ^ {
            NSLog(@"hello world");
        };
        NSLog(@"%@",[block1 class]);
        ///__NSStackBlock__
        int age = 10;  //auto局部变量
        void(^block2)(void) = ^{
            NSLog(@"age = %d",age);
        };
        NSLog(@"%@",[block2 class]);
        ///__NSGlobalBlock__
        NSLog(@"%@",[^{
            NSLog(@"height = %d",height);
        } class]);
        
    }
    控制器输出打印结果
    2019-02-22 10:15:48.642882+0800 Block01[20101:1139963] __NSGlobalBlock__
    2019-02-22 10:15:48.643117+0800 Block01[20101:1139963] __NSStackBlock__
    2019-02-22 10:15:48.643135+0800 Block01[20101:1139963] __NSGlobalBlock__
    
    

    我们平时使用 block 的时候 一般都有 copy 操作,这样做是为什么呢?

    image.png

    2019-02-22 10:29:11.315472+0800 Block01[23997:1178680] NSStackBlock

    block是分配在栈内存的 当函数作用域结束的时候 block 就会被内存回收,那么这个时候去调用 block 内部代码 ,这个时候 block 可能已经销毁了 它捕获的 string 变量也可能已经不存在了 这个时候输出 string 的值 就会造成坏内存访问.

    image.png

    如何能够让 block 一直存在内存中呢 ?
    调用[ block copy]就可以将 block 从栈内存拷贝到堆内存 ,在使用 block 的时候就不会出现 block 已经被销毁的情况.

    void (^block)(void);
    void testBlock() {
        NSString *string = @"dzb";
        block = [^{
            NSLog(@"string = %@",string);
        } copy];
        NSLog(@"%@",[block class]);
    }
    
    ///控制台输出结果
    2019-02-22 10:33:54.178636+0800 Block01[25341:1191775] __NSMallocBlock__
    2019-02-22 10:33:57.641726+0800 Block01[25341:1191775] string = dzb
    
    

    下边的图可以总结出 block 的类型


    image.png

    在我们平时开发中 定义 block 的地方 和 调用 block 地方可能不在一个地方,这种情况下就需要将 block copy 保证 block 不被销毁

    image.png

    2019-02-22 10:39:41.851458+0800 Block01[26979:1208502] NSMallocBlock
    2019-02-22 10:39:41.851682+0800 Block01[26979:1208502] string = dzb

    好了,我是大兵布莱恩特,欢迎加入博主技术交流群,iOS 开发交流群

    QQ20180712-0.png

    相关文章

      网友评论

        本文标题:Block的三种类型

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