美文网首页
OC中的Block(三)

OC中的Block(三)

作者: aaayia | 来源:发表于2018-11-26 19:46 被阅读3次

    block的类型

    block有3种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承自NSBlock类型

    • __NSGlobalBlock__ (_NSConcreteGlobalBlock )
    • __NSStackBlock__ (_NSConcreteStackBlock )
    • __NSMallocBlock__ (_NSConcreteMallocBlock )
    应用程序内存分配
    程序区域 .text区
    数据区域 .data区
    堆区
    栈区
    不同类型block的存放区域

    生成不同类型的block

    block类型 环境
    NSGlobalBlock(数据区) 没有访问auto变量
    NSStackBlock(栈区) 访问了auto变量
    NSMallocBlock(堆区) NSStackBlock调用了copy

    每一种类型的block调用copy后的结果如下所示:

    block类型 副本源的配置存储域 复制效果
    NSGlobalBlock(数据区) 栈区 从栈复制到堆区
    NSStackBlock(栈区) 程序的数据区 什么也不做
    NSMallocBlock(堆区) 堆区 引用计数增加

    block的copy

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

    • block作为函数返回值时
    • 将block赋值给__strong指针时
    • block作为Cocoa API中方法名含有usingBlock的方法参数时
    • block作为GCD API的方法参数时

    MRC下block属性的建议写法

    @property (copy, nonatomic) void (^block)(void);`
    

    ARC下block属性的建议写法

    @property (strong, nonatomic) void (^block)(void);
    @property (copy, nonatomic) void (^block)(void);
    

    对象类型的auto变量

    当block内部访问了对象类型的auto变量时

    • 如果block是在栈上,将不会对auto变量产生强引用

    • 如果block被拷贝到堆上

    1. 如果block被拷贝到堆上
    2. copy函数内部会调用_Block_object_assign函数
    3. _Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用
    函数 点用时机
    __main_block_copy_0 栈上的block复制到堆时
    __main_block_dispose_0 堆上的block被废弃时
    //block被拷贝到堆上时调用
    static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
    
    //会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用
    _Block_object_assign((void*)&dst->obj,
                             (void*)src->obj,
                             8/*BLOCK_FIELD_IS_BYREF*/);
    }
    
    //block从堆上移除时调用
    static void __main_block_dispose_0(struct __main_block_impl_0*src) {
    //会自动释放引用的auto变量(release)
    _Block_object_dispose((void*)src->obj,
                              8/*BLOCK_FIELD_IS_BYREF*/);
    }
    

    __weak修饰符

    __weak修饰符可以是block生成的结构体中捕获的变量为__weak变量..则可以对变量进行弱引用,解决循环引用问题

    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      //捕获__weak变量
      NSString __weak *name;
      .
      .
      .
    };
    

    在使用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
    

    __block修饰符

    __block可以用于解决block内部无法修改auto变量值的问题.但是__block不能修饰全局变量、静态变量(static)

    编译器会将__block变量包装成一个对象

    __block int age = 13;
    ^{
        NSLog(@"%d", age);
    }();
    

    会生成一下C++代码:

    struct __main_block_impl_1 {
      struct __block_impl impl;
      struct __main_block_desc_1* Desc;
      __Block_byref_age_2 *age; // by ref
      __main_block_impl_1(void *fp, struct __main_block_desc_1 *desc, __Block_byref_age_2 *_age, int flags=0) : age(_age->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    
    struct __Block_byref_age_2 {
      void *__isa;
    __Block_byref_age_2 *__forwarding;
     int __flags;
     int __size;
     int age;
    };
    

    相关文章

      网友评论

          本文标题:OC中的Block(三)

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