block原理

声明:本文仅供记忆使用,并不适合新手小白观看

  • block本质上也是一个OC对象,它内部也有个isa指针

block的变量捕获

  • 捕获机制
  • auto变量捕获

block的类型

  • block有3种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承自NSBlock类型
    NSGlobalBlock (_NSConcreteGlobalBlock) 全局区 copy后什么也不做
    NSStackBlock (_NSConcreteStackBlock) 栈区 copy后栈区到堆区
    NSMallocBlock (_NSConcreteMallocBlock) 堆区 copy后引用计数加1

  • 3种类型生成场景

block的copy

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

    1. block作为函数返回值时
    2. block赋值给__strong指针时
    3. block作为Cocoa API中方法名含有usingBlock的方法参数时
    4. block作为GCD API的方法参数时
  • MRC下block属性的建议写法

    1
    @property (copy, nonatomic) void (^block)(void);
  • ARC下block属性的建议写法

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

对象类型的auto变量

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

  • 如果block是在上,将不会对auto变量产生强引用
  • 如果block被拷贝到上,会对auto变量产生强引用或弱引用

    会调用block内部的copy函数 -> _Block_object_assign函数 ,函数会根据auto变量的修饰符(__strong__weak__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用

  • 如果block从堆上移除自动释放引用的auto变量

    会调用block内部的dispose函数 -> _Block_object_dispose函数,函数会自动释放引用的auto变量(release)

__block修饰符

  • __block可以用于解决block内部无法修改auto变量值的问题
  • __block不能修饰全局变量静态变量(static)
  • 编译器会将__block变量 包装成一个对象
  • 当block在上时,并不会对__block变量产生强引用
  • 当block被copy到时,会对__block变量形成强引用(retain)

    会调用block内部的copy函数->_Block_object_assign函数 -> 强引用)

  • 当block从堆中移除时,自动释放引用的__block变量

    会调用block内部的dispose函数 -> _Block_object_dispose函数,函数会自动释放引用的__block变量(release)

  • __block中__forwarding指向
  • __block变量对对象的引用和block对auto变量引用是一样的,详见上面对【#对象类型的auto变量】

解决block循环引用

参考资料

将oc代码转化为c++代码

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m