type
status
date
slug
summary
tags
category
icon
password
我们在针对
Block的剖析在进一步加深,了解了Block如何截获基本类型,了解Block的类型和copy操作,下面我们开始进入Block的内存管理世界。Block的内存管理,主要针对捕获外部对象类型的
auto变量。根据Block捕获auto基本变型的规律,针对对象,仍然适用。
auto变量捕获后,Block中变量的类型和变量原类型一致;
static变量捕获后,Block对应的变量是对应变量的指针类型;
那么,
auto对象与基本类型在Block内部有什么区别呢。我们将从两方面讨论:
Block是如何捕获对象类型的?
Block内部是如何管理对象类型的?
一、捕获对象类型
以下代码位于Block捕获对象类型-
Test.m中。1. Block对象结构体
将下面代码重写:
以上
Block对象重写后的结构体如下:可以看到:
Block对象仍然捕获auto变量后,保留了person对象的类型。2.Desc及Func
进一步观察
Block对象中的Desc结构以及Func:那么与基本类型的捕获区别在哪里呢?
我们观察与之前基本类型的区别,
Func基本没有区别,Desc有区别,多了两个函数指针:- void (*copy)
- void (*dispose)
那么继续查看这两个函数:
针对这两个函数,它们的作用就是:
函数 | 作用 | 调用时机 |
__Test__test_block_copy_0 | 调用 _Block_object_assign,相当于retain,将对象赋值在对象类型的结构体变量 __Test__test_block_impl_0中。 | 栈上的Block复制到堆时 |
__Test__test_block_dispose_0 | 调用 _Block_object_dispose,相当于release,释放赋值在对象类型的结构体变量中的对象。 | 堆上Block被废弃时 |
二、内存管理
在我们观察了
Block对象捕获对象类型的内部结构之后,我们基本就能了解Block内部是如何管理的:- 在栈上的Block对象复制到堆上,对
person进行retain;
- 在堆上Block被废弃时,对
person进行废弃;
以上操作在
ARC环境下,由系统帮助我们完成,但在MRC下,我们仍然要自己管理。下面,我们就一步一步探索验证不同情境下的对象类型内存管理。
2.1 Block在栈上
我们将项目调成
MRC环境,并在类BFPerson重写dealloc测试如下代码:

可以看到,在
[person release]后,Block内部再次访问直接崩溃,说明Block内并没有对person对象进行强引用,使得person在内存中释放。总结:
在栈空间,Block不会对auto变量进行强引用。
2.2 Block在堆上
2.1 Block强引用对象类型
我们将2.1,即上节中的代码,在ARC环境下再次试验,打印结果如下:
Block捕获对象类型[94670:4794884] begin Block捕获对象类型[94670:4794884] class: __NSMallocBlock Block捕获对象类型[94670:4794884] age 28 Block捕获对象类型[94670:4794884] end Block捕获对象类型[94670:4794884] BFPerson dealloc
针对以上结果:
ARC情况下,在Block赋值给__strong指针时,栈上的Block自动拷贝到堆;
- 拷贝的同时会将
person对象进行retain操作,在这里相当于强引用;
- 调用
block时,即使person出了大括号,系统会release一次,但由于block内部仍然强引用person,所以不会销毁;
- 在打印"end"后,
block销毁,那么对person将进行一次release操作,所以person对象销毁。
2.2 Block弱引用对象类型
我们将
block内部引用的auto变量改为__weak,我们知道__weak表示的是弱引用指针。上面代码输出的测试结果如下:
Block捕获对象类型[94923:4823185] begin Block捕获对象类型[94923:4823185] class: __NSMallocBlock Block捕获对象类型[94923:4823185] BFPerson dealloc Block捕获对象类型[94923:4823185] age 0 Block捕获对象类型[94923:4823185] end
从输出结果我们很明显的看出,只要出了大括号,
person对象就被销毁了,此后block调用,获取到的结果是0,这其实并不是person对象的age值。我们将上面代码重写为C++代码,看看Block内部到底发生了什么?
此时发生错误:

针对上面问题,我们指定
ARC下的运行时系统版本即可:得到的Block对象结构体:
其实上面大体和强引用对象类似,只是其对应
copy和dispose函数针对强引用和弱引用有所不同。三、 总结

参考
示例代码