Block 03 - 内存管理
Block 的 copy
-
在 ARC 环境下,编译器会根据情况自动将栈上的 Block 复制到堆上:
- Block 作为函数返回值时。
- 将 Block 赋值给 __strong 指针时。
- Block 作为 Cocoa API 中方法名含有 UsingBlock 的方法参数时。
- Block 作为 GCD API 的方法参数时。
在 MRC 环境下 Block 属性的建议写法:
@property(nonatomic, copy) void (^block)(void);
在 ARC 环境下 Block 属性的建议写法:
@property(nonatomic, strong) void(^block)(void);
@property(nonatomic, copy) void(^block)(void);
当 Block 内部访问了对象类型的 auto 变量、__block 对象时
- 当 Block 在栈上时,对它们都不会进行强引用。
- 当 Block 被拷贝到堆上时:
- 会调用 Block 内部的 copy 函数。
- copy 函数内部会调用 _Block_object_assign 函数。
- _Block_object_assign 函数会对 __block 对象进行强引用。
- _Block_object_assign 函数会根据 auto 变量的修饰符(__strong, __weak, __unsafe_unretained)做出相应的操作,进行强引用(retain)或弱引用。
- 当 Block 从堆上移除时:
- 会调用 Block 内部的 dispose 函数。
- dispose 函数内部会调用 _Block_object_dispose 函数。
- _Block_object_dispose 函数会自动释放被强引用的对象(release)。
_Block_object_assign((void*)&dst->o, (void*)src->o, 3/*BLOCK_FIELD_IS_OBJECT*/); _Block_object_assign((void*)&dst->b, (void*)src->b, 8/*BLOCK_FIELD_IS_BYREF*/); _Block_object_dispose((void*)src->o, 3/*BLOCK_FIELD_IS_OBJECT*/); _Block_object_dispose((void*)src->b, 8/*BLOCK_FIELD_IS_BYREF*/);
代码中如果使用了 __weak,在使用 clang 将 Objective-C 转换为 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== class.m -o class.cpp
__block 对象的内存管理
- 当 __block 对象在栈上时,不会对被包装的变量指向的对象进行强引用。
- 当 __block 对象被拷贝到堆上时:
- 会调用 __block 对象内部的 __Block_byref_id_object_copy 函数。
- __Block_byref_id_object_copy 函数内部会调用 _Block_object_assign 函数。
- _Block_object_assign 函数会根据变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,进行强引用(retain,仅限于 ARC 环境)或弱引用。
- 当 __block 对象从堆上移除时:
- 会调用 __block 变量内部的 __Block_byref_id_object_dispose 函数。
- __Block_byref_id_object_dispose 函数内部会调用 _Block_object_dispose 函数。
- _Block_object_dispose 函数会自动释放被强引用的对象(release)。