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的惰性属性。 此属性引用将nametext组合为HTML字符串片段的闭包。 asHTML属性的类型为() -> String ,或“不带任何参数并返回String值的函数”。

现在,启动HTMLElement类并为其引用段落。

不幸的是,如上所述, HTMLElement类在HTMLElement实例和用于其默认asHTML值的闭包之间创建了强大的引用周期。 循环的外观如下:

实例的asHTML属性对其关闭有很强的引用。 但是,由于闭包在其主体内引用了self (作为引用self.nameself.text一种方式),因此闭包捕获了 self,这意味着它拥有对HTMLElement实例的强引用。

[unown self]定义捕获列表。 关闭将称为无主自我。

由于自我的生命比封闭的生命更长,因此我们使用无主的生命来应对。

如果未声明为弱,则委托创建强参考周期:

假设有一个自定义的UiView类,并且在UIView中单击某个按钮时,我想更改某些属性或在UIViewController上显示一些弹出窗口。 因此,最常见的创建协议并将其委托声明为协议的可选类型的方法(假设我们没有在UIView中将其声明为弱(这是开发人员经常犯的错误),并且UIViewController具有对UIView的强大引用。

  • UIView具有很强的委托参考。
  • UIViewController具有UIView的强大参考。
  • 当实现协议并在UIViewController中使用委托时,我们编写如下代码:xyzView.delegate = self。
  • 这将在UIViewController和委托之间创建一个强大的引用。
  • 并且按照第一行,即(UIView具有强大的委托参考。)
  • 它将在UIView和UIViewController之间创建强大的引用周期。

简而言之,为了避免出现上述情况,请使用弱势代表。

Interesting Posts