美文网首页
OC 基础-Block类型

OC 基础-Block类型

作者: 我是卖报的小行家 | 来源:发表于2021-03-07 23:21 被阅读0次

    OC基础-Block(3)Block的类型
    Block有三种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承NSBlock类型
    NSGlobalBlock (NSConcreteGlobalBlock) 没有访问auto变量
    NSStackBlock (NSConcreteStackBlock) 访问了auto变量
    NSMallocBlock (NSConcreteMallocBlock) __NSStackBlock调用了copy
    看图更清楚

    一般全局变量存于数据段,alloc出来的存于堆段,局部变量存于栈段(一般数据不宜很大),类对象内存一般存于数据段
    Block做为函数返回值的时候,(ARC情况下)系统会自动给block做copy处理

    每一种类型的block调用copy后的结果如下图所示
    Block类型 副本源的配置存储域 复制效果
    _NSConcreteStackBlock 栈 从栈复制到堆
    _NSConcreteGlobalBlock 程序的数据区域 什么也不用做
    _NSConcreteMallocBlock 堆 引用计数增加

    block类型图 内存分配地质图

    栈上的内存系统会自动回收

    栈空间的block 不会对 对象进行强引用

    堆空间的block 可能会对对象产生强引用:

    如果是weak指针,不会强引用

    如果是strong指针,会强引用

    堆上的内存是由程序员控制,所以一般将block 拷贝到堆上,让程序员控制他与内部变量的生命周期
    //上代码
    1.NSGlobalBlock

    #import <Foundation/Foundation.h>
    
    typedef void(^MJBlock)(void);
    
    MJBlock myBlock(){
        
        return ^{
            NSLog(@"-----------");
        };
    }
    
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
    
            MJBlock block = myBlock();
            block();
            
            NSLog(@"%@",[block class]);
            
        }
        return 0;
    }
    
    //打印结果
    2021-03-07 21:19:31.897780+0800 DoBlock[74885:2090486] -----------
    2021-03-07 21:19:31.898430+0800 DoBlock[74885:2090486] __NSGlobalBlock__
    

    原因分析:因为里面没有访问到任何的auto变量,所以MJBlock为NSGlobalBlock

    代码2.NSMallocBlock

    #import <Foundation/Foundation.h>
    
    typedef void(^MJBlock)(void);
    
    MJBlock myBlock(){
        
        int age = 20;
        return ^{
            NSLog(@"-----------age%d",age);
        };
    }
    
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
    
            MJBlock block = myBlock();
            block();
            
            NSLog(@"%@",[block class]);
            
        }
        return 0;
    }
    
    //打印结果
    2021-03-07 21:23:36.045133+0800 DoBlock[74961:2094241] -----------age = 20
    2021-03-07 21:23:36.045757+0800 DoBlock[74961:2094241] __NSMallocBlock__
    

    原因分析:咦,不是访问了auto变量,应该是NSStackBlock吗?其实是Block做为返回值,ARC环境下默认帮我们做了一次copy处理,__NSStackBlock调用了copy处理所以就是NSMallocBlock类型咯
    此时我们做一个总结

    在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况

    1)block作为函数返回值时
    2)将block赋值给__strong指针时

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            int age = 50;
            MJBlock block = ^{
                NSLog(@"----- = %d",age);
            };//强引用
            NSLog(@"%@",[block class]);
            
        }
        return 0;
    }
    //打印结果:2021-03-07 21:39:42.777653+0800 DoBlock[75249:2109355] __NSMallocBlock__
    
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            int age = 30;
            NSLog(@"%@",[^{
                NSLog(@"%d",age);
            } class]);
    
        }
        return 0;
    }
    //因为只是引用了auto变量所以
    //打印结果:2021-03-07 21:40:37.273735+0800 DoBlock[75269:2110555] __NSStackBlock__
    
    

    3)block作为Cocoa API中方法名含有usingBlock的方法参数时

            NSArray * array = @[];
            
            [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                        
            }];
    //block最终会搬到堆上面去
    

    4)block作为GCD API的方法参数时
    所以在这些情况下block类型都为NSMallocBlock类型。

    Tip:
    在使用clang转换OC为C++代码时,可能会遇到以下问题
    cannot create __weak reference in file using manual reference

    解决方案:支持ARC、指定运行时系统版本,比如
    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m

    相关文章

      网友评论

          本文标题:OC 基础-Block类型

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