美文网首页iOS进阶
06.2-OC中block的类型

06.2-OC中block的类型

作者: 光强_上海 | 来源:发表于2020-06-14 22:26 被阅读0次

    block的类型

    我们创建一个新工程,然后在main函数中创建几个block,在ARC环境下运行,代码如下:

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // insert code here...
            
            void (^block1)(void) = ^{
                NSLog(@"111");
            };
            
            NSLog(@"%@",[block1 class]); // __NSGlobalBlock__
            NSLog(@"%@",[[block1 class] superclass]); // __NSGlobalBlock
            NSLog(@"%@",[[[block1 class] superclass] superclass]); // NSBlock
            NSLog(@"%@",[[[[block1 class] superclass] superclass] superclass]); // NSObject
            
            继承关系:__NSGlobalBlock__ :__NSGlobalBlock :NSBlock :NSObject
            
            int a = 10;
            void (^block2)(void) = ^{
                NSLog(@"%d", a);
            };
            
            NSLog(@"%@", [block1 class]); // __NSGlobalBlock__
            
            NSLog(@"%@", [block2 class]); // __NSMallocBlock__
            
            NSLog(@"%@", [^{
                NSLog(@"%d", a);
            } class]); // __NSStackBlock__
        }
        return 0;
    }
    

    从上面的代码打印我们可以看出,block最终继承自NSObject对象,并且我们可以看出打印出的block有三种类型:

    • NSGlobalBlock
    • NSMallocBlock
    • NSStackBlock

    接下来我们看这三种block有何区别,后面的代码运行环境我们切换至MRC模式

    我们修改main函数内的代码如下:

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // insert code here...
            
            // block1内部没有访问auto变量
             void (^block1)(void) = ^{
                 NSLog(@"111");
             };
             
             NSLog(@"%@", [block1 class]); // __NSGlobalBlock__
            
             int a = 10;
             
             // block2内部访问了auto变量
             void (^block2)(void) = ^{
                 NSLog(@"%d", a);
             };
             
             NSLog(@"%@", [block2 class]); // __NSStackBlock__
        }
        return 0;
    }
    

    从上面的代码我们可以得出结论:

    • block1内部没有访问auto变量类型为:NSGlobalBlock
    • block2内部访问auto变量类型为: NSStackBlock

    接下来我们继续改造main函数中的代码如下:

    void (^block)(void);
    
    void test() {
        int a = 10;
        
        // block内部访问了auto变量,所以block的内存地址分布在栈上,栈上内存的特点是出了作用域就会销毁
        block = ^{
            NSLog(@"%d", a); // -272632888
        };
        
        NSLog(@"%@", [block class]); // __NSStackBlock__
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // insert code here...
            
            // 当执行完test函数后,栈上分配的内存就会销毁
            test();
            
            // 执行block,栈上的内存已经销毁
            block();
        }
        return 0;
    }
    

    对于block内部有访问到auto变量,最好将block放到堆内存中,因为堆内存是开发者来管理,就不存在提前销毁的情况了

    那么如何将栈内存上的block放到堆内存?我们可以对栈上的block进行copy操作将其拷贝到堆内存中,上面的代码修改如下:

    void (^block)(void);
    
    void test() {
        int a = 10;
        
        block = [^{
            NSLog(@"%d", a); // 10
        } copy];
        
        NSLog(@"%@", [block class]); // __NSMallocBlock__
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // insert code here...
            
            test();
            block();
        }
        return 0;
    }
    

    block的类型总结如下图所示:

    image image

    讲解示例Demo地址:https://github.com/guangqiang-liu/06.2-BlockDemo2

    更多文章

    相关文章

      网友评论

        本文标题:06.2-OC中block的类型

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