ARC(iOS)
Swift使用自动引用计数 (ARC)来跟踪和管理应用程序的内存使用情况。 引用计数仅适用于类的实例。 结构和枚举是值类型,而不是引用类型,并且不通过引用存储和传递。
在本教程中,我将解释:
ARC如何工作以及如何简化内存管理?
什么是强引用,弱引用和无所有权?
什么是强参考周期,它如何导致内存泄漏和问题?
如何避免闭包和委托中的强刷新周期?
ARC如何工作?
每当创建类的实例时,ARC都会分配内存块来存储有关该实例的信息,并且当不需要类实例时,ARC会通过从内存中删除该实例来释放内存。
现在,ARC可以跟踪/计算引用该实例的变量,常量或属性的数量。 如果count为零,则ARC从内存中删除该实例。 如果实例的引用仍然存在,ARC会将其保留在内存中。
注意:我们不必显式删除实例或担心内存管理。 ARC为我们做到了。
强参考:
默认情况下,每个引用都是强引用,直到使用显式弱引用或无所有权引用为止。
引用被称为“强引用”,因为它在该实例上保持坚挺,并且只要该强引用仍然存在,就不允许对其进行重新分配。
为了理解弱点和无主点,我们需要了解一个常见的未知问题,即强参考周期。
现在给约翰分配一个公寓,让我们说右图所示的unit4A。 约翰也是unit4A的租户。 这将创建一个强大的参考周期,即使将john和unit4A设置为nil,人实例和单元实例的参考计数也将为1,并且ARC将无法执行任何操作,并且会发生内存泄漏。
将john设置为nil并将unit4A设置为nil后,将删除var链接,但由于发生了强烈的引用循环,因此仍然不会调用deinit。
现在,我们已经清楚地了解了这个问题(如果不能再阅读2-3次,然后在Playground中尝试一下,看看是否调用了deinit),那么我们现在就可以解决它。
因此,现在是讨论弱者和无主者的好时机:
使用类类型的属性时,Swift提供了两种解决强引用周期的方法:弱引用和无主引用。
弱引用和无主引用使引用周期中的一个实例可以引用另一个实例, 而无需对其进行严格控制。 然后,这些实例可以相互引用,而无需创建强大的引用周期。
当另一个实例的生存期较短时(即,另一个实例可以首先被释放时),请使用弱引用。 在上面的“ Apartment
示例中,对于公寓来说,在其生命周期的某个时候不能有任何租户是合适的,因此在这种情况下,弱引用是打破引用周期的一种适当方法。 相反,当另一个实例具有相同的生存期或更长的生存期时,请使用无主引用。
因此,在上面的示例中,可以将Apartment的租户声明为弱者,因为租户的生存期比Apartment短,即Apartment可以拥有一个租户,并且该公寓的生活可能是空的。
在使用弱解决强引用循环的同时,确定哪个实例将是短命的(这也取决于设计和要求)。
如果您仍然有疑问,请再次阅读此行:
“当另一个实例具有相同的生存期或更长的生存期时,将使用一个无主引用。”
封闭的强大参考周期:
如果将闭包分配给类实例的属性,并且闭包的主体捕获该实例,则也会发生强引用循环。 由于闭包的主体访问实例的属性(例如self.someProperty
,或者闭包在实例上调用方法self.someMethod()
例如self.someMethod()
,可能会发生这种捕获。 在任何一种情况下,这些访问都会导致闭包“捕获” self
,从而创建一个强大的参考周期。
之所以会发生这种强烈的引用循环,是因为像类一样,闭包是引用类型。
将闭包分配给属性时,就是在分配对该闭包的引用 。 本质上,这是与上述相同的问题-两个强引用使彼此保持生命。 但是,这次不是两个类实例,而是一个彼此保持生命的类实例和一个闭包。
HTMLElement
类定义了一个名为asHTML
的惰性属性。 此属性引用将name
和text
组合为HTML字符串片段的闭包。 asHTML
属性的类型为() -> String
,或“不带任何参数并返回String
值的函数”。
现在,启动HTMLElement类并为其引用段落。
不幸的是,如上所述, HTMLElement
类在HTMLElement
实例和用于其默认asHTML
值的闭包之间创建了强大的引用周期。 循环的外观如下:
实例的asHTML
属性对其关闭有很强的引用。 但是,由于闭包在其主体内引用了self
(作为引用self.name
和self.text
一种方式),因此闭包捕获了 self,这意味着它拥有对HTMLElement
实例的强引用。
[unown self]定义捕获列表。 关闭将称为无主自我。
由于自我的生命比封闭的生命更长,因此我们使用无主的生命来应对。
如果未声明为弱,则委托创建强参考周期:
假设有一个自定义的UiView类,并且在UIView中单击某个按钮时,我想更改某些属性或在UIViewController上显示一些弹出窗口。 因此,最常见的创建协议并将其委托声明为协议的可选类型的方法(假设我们没有在UIView中将其声明为弱(这是开发人员经常犯的错误),并且UIViewController具有对UIView的强大引用。
- UIView具有很强的委托参考。
- UIViewController具有UIView的强大参考。
- 当实现协议并在UIViewController中使用委托时,我们编写如下代码:xyzView.delegate = self。
- 这将在UIViewController和委托之间创建一个强大的引用。
- 并且按照第一行,即(UIView具有强大的委托参考。)
- 它将在UIView和UIViewController之间创建强大的引用周期。
简而言之,为了避免出现上述情况,请使用弱势代表。