OC对象 – Block-对象类型的auto变量

💡 原文中文,约2100字,阅读约需5分钟。
📝

内容提要

本文讨论了在Block内部访问目标类型的auto变量时的影响。当Block在栈上时,不会对auto变量产生强引用;当Block被拷贝到堆上时,会调用copy函数并根据auto变量的修饰符进行相应操作;当Block从堆上移除时,会调用dispose函数并释放引用的auto变量。

🔎

延伸解读

Block 内存管理的关键:栈与堆的差异

文章通过对比实验清晰展示了 Block 在栈上和堆上对 auto 变量的不同处理方式。栈上的 Block 不会强引用对象,因此对象能及时释放;而堆上的 Block 会通过 copy 函数持有对象,延长其生命周期。理解这一差异有助于避免内存泄漏或意外释放,尤其在手动管理内存的 MRC 环境下。

copy 与 dispose:Block 管理对象引用的底层机制

当 Block 被拷贝到堆上时,其结构体中会新增 copy 和 dispose 函数。copy 函数内部调用 _Block_object_assign,根据 auto 变量的修饰符(如 __strong、__weak)决定是强引用还是弱引用;dispose 函数则调用 _Block_object_dispose 来释放引用。这解释了为何堆上的 Block 能安全持有对象,而栈上的 Block 不能。

NSStackBlock 的特殊行为:为何不持有对象

文章指出,NSStackBlock 类型的 Block 本身随时可能被释放,因此没有必要强持有其访问的 auto 变量。实验也验证了这一点:当 Block 未被强引用变量接收时,person 对象在离开作用域后立即释放。这提醒开发者,Block 的类型会影响对象生命周期,需根据场景选择是否用 strong 变量接收。

❓

Q&A

Block在栈上和堆上对auto变量的引用有什么不同?

如果Block在栈上,不会对auto变量产生强引用;如果Block被拷贝到堆上,则会根据修饰符进行相应的引用管理。

如何创建一个观察对象释放时机的类?

可以创建一个ZSXPerson类,并在其dealloc方法中打印信息,以观察对象何时被释放。

Block内部访问目标类型的auto变量时会发生什么?

Block内部访问目标类型的auto变量时,如果Block持有该变量的强引用,变量在作用域外仍然存在,直到Block被释放。

NSStackBlock类型的Block有什么特点?

NSStackBlock类型的Block不需要强持有目标类型的auto变量,能够及时释放这些变量。

Block的copy和dispose函数有什么作用?

copy函数用于管理Block所持有变量的引用关系,而dispose函数用于释放引用的auto变量。

如何判断Block是否持有目标类型的auto变量?

可以通过观察Block的类型和作用域来判断,如果Block是NSStackBlock类型,则不会持有目标类型的auto变量。

➡️

继续阅读