Swift中的内存管理:了解强引用,弱引用和未引用
在我们正在执行的所有编码的背后,您可能在编写代码时注意到一些变量,它们引用了strong
, weak
或unowned
。 他们到底是什么意思? 通过以strong为参考声明所有变量,是否会使您的变量更强?
strong
, weak
或unowned
的用法实际上与Swift中称为自动引用计数(ARC)的内存管理有关。 让我们放慢一点,尝试了解这里的含义。 因此,ARC实际上会进行自动引用计数。 在计算机科学的定义中, 引用计数是一种将引用,指针或句柄的数量存储到资源(例如对象,块或内存,磁盘空间或其他资源)中的技术。 简而言之,ARC实际上有助于将引用存储到内存中,并有助于在不使用引用时进行清理。
另外,在这种情况下,引用计数仅适用于类的实例,不适用于结构和枚举,因为它们都是值类型,而不是引用类型。
在进一步介绍之前,为什么内存管理这么重要? 由于内存管理在分配内存中起着巨大的作用,因此程序确实可以在用户的请求下执行,并且在不再需要时可以免费重用,因此这确实是一个大问题。
但是,如果您耗尽内存,会发生什么呢?
- 该任务将停止执行,这意味着您将无法执行任何任务。
- 该任务可能不会继续执行,但会继续运行,直到达到极限并且程序崩溃为止。
- 您可能不希望用户使用越野车程序。
什么是自动引用计数(ARC)?
如官方文档中所述,
内存管理在Swift中“行之有效”,您无需自己考虑内存管理。 当不再需要类实例使用的实例时,ARC会自动释放它们。
ARC还跟踪信息,例如了解代码之间的关系,因此ARC能够有效地管理内存资源。
ARC如何工作?
每次通过init()
创建类实例时,ARC都会自动分配一些内存来存储信息。 更具体地说,该内存块保存实例以及属性值。 当不再需要该实例时,将调用deinit()
并且ARC将释放该实例的内存空间。
使用下面的代码,这很容易解释,但是我仍然希望您了解代码的作用。 这是带有Person
实例和Gadget
实例的两个类的示例, Gadget
具有init
方法,该方法将设置实例的属性,这意味着将任何信息分配到内存中。 同样,在deinit
,我们将看到实例被释放,这意味着包含信息的内存将在我们的情况下释放。
强vs弱vs无主-事实
- 通常,在创建属性时,除非引用被声明为
weak
或unowned
否则引用为强。 - 将属性标记为
weak
,它将不会增加引用计数 - 介于两者之间的是
unowned
引用,它们既不是强引用,也不是可选类型。 编译器将假定对象没有被释放,因为引用本身仍然保持分配状态。
强大的参考
让我们看下面的例子。 我们有一个Person
类型的变量,其引用为“ Kelvin”,一个Gadget
类型的变量,其引用为“ iPhone 8 Plus”。
查看控制台消息。 您应该看到两个变量都已正确初始化。
现在,添加以下代码kelvin
分配iphone
并设置iphone
的owner
。 在将kelvin
和iphone
设置为nil
之前,请确保插入代码:
好的,在Playgrounds中再次运行代码。 您应注意,控制台仅显示有关初始化的消息。
显然,当我们中断强引用时,引用计数不会降为零,并且实例也不会被ARC释放。 为什么? 让我直观地说明这个问题。 即使在kelvin
和iphone
都设置为nil
情况下, Person
实例和Gadget
实例之间的强引用也会保留并且不能被破坏。
这就是我们所说的强参考周期,导致您的应用程序内存泄漏。 为了打破强引用周期并防止内存泄漏,您将需要使用weak
引用和未unowned
引用。
参考不足
弱引用始终被声明为可选类型,因为变量的值可以设置为nil
。 为了指示引用为弱引用,您只需在属性或变量声明之前添加weak
关键字,如下所示:
如您所见,控制台消息中,两个变量现在都已正确释放。 将owner
变量更改为weak
,两个实例之间的关系看起来与前一个实例略有不同:
使用weak
引用,当您将kelvin
设置为nil
,可以正确地释放该变量,因为不再有指向Person
实例的强引用。
无人参考
无主引用与弱引用非常相似,可用于解决强引用循环。 最大的区别在于,无主引用始终具有价值。 ARC不会将未拥有的引用的值设置为nil
。 换句话说,引用被声明为非可选类型。
仅当确定引用始终引用尚未取消分配的实例时,才使用无主引用。 如果在释放该实例后尝试访问一个未拥有的引用的值,则会收到运行时错误。
由于无主引用不能是可选的,因此我们将对示例代码进行一些修改:
让我们尝试通过将kelvin
变量声明为nil
来打破强引用,然后看看会发生什么。
如您所见, Person
和Gadget
的实例已正确释放。 由于我们打破了Person
实例的强引用(即kelvin
),因此实例被释放。 因此,由于没有对Gadget
实例的强烈引用,它会自动释放。
结论
希望您现在对强项,弱项和无主引用有更好的了解。 Xcode为开发人员提供了内置工具来调试内存问题。 例如,如果要检测内存泄漏,可以转到菜单并选择“产品”>“配置文件”>“泄漏”。 如果您想让我们写更多有关内存管理和调试技巧的信息,请给我们留言并告知我们。