翻译: Swift 中的委托保留周期 如何在“纯”Swift(没有@objc)中进行弱协议引用

Posted 架构师易筋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了翻译: Swift 中的委托保留周期 如何在“纯”Swift(没有@objc)中进行弱协议引用相关的知识,希望对你有一定的参考价值。

您需要将协议类型声明为AnyObject.

protocol ProtocolNameDelegate: AnyObject {
    // Protocol stuff goes here
}

class SomeClass {
    weak var delegate: ProtocolNameDelegate?
}

使用AnyObject你说只有类class可以符合这个协议,而结构struct或枚举enum不能。

为什么委托应该是弱 var?

1. 什么是保留周期和内存泄漏?

ios 中的内存泄漏是由于保留周期而无法释放内存中分配的空间量。由于 Swift 使用自动引用计数 (ARC),当两个或多个对象相互持有强引用时,就会发生保留循环。结果,这些对象在内存中相互保留,因为它们的保留计数永远不会减少到 0,这将阻止deinit被调用和内存被释放。

2、我们为什么要关心内存泄漏?

内存泄漏会逐渐增加应用程序中的内存占用,当它达到某个阈值时,操作系统 (iOS) 会触发内存警告。如果未处理该内存警告,您的应用程序将被强制终止,即OOM (内存不足)崩溃。

我们将设计协议和类以显示代表的保留周期。

protocol SendDataDelegate{}

class SenderVC {
	var delegate: SendDataDelegate?

	deinit {
		print("Deinitialized.")
	}
}

class REceiverVC: SendDataDelegate {
	lazy var senderVC: SendVC = {
		let vc = SenderVC()
		vc.delegate = self
		return vc
	}()

	deinit {
		print("Deinitialized.")
	}
}

使用lazy关键字我们不会初始化委托,这意味着现在没有内存泄漏。让我们打破它。

var receiverVC: ReceiverVC? = ReceiverVC()
receiverVC?.senderVC

对象将被创建,并且会有内存泄漏。

让我们想象一下这种关系。

有一个保留周期。即使您将receiverVC 设置为nil,ReceiverVC 和SenderVC 之间也存在引用计数。
要摆脱这种情况,请将关系/引用之一设为弱。

class SenderVC {
	weak var delegate: SendDataDelegate?
	
	deninit {
		print("Deinitialized.")
	}
}

它迫使我们向相关协议添加仅类一致性

弱引用仅针对引用 类型定义。(闭包也是引用类型,但闭包不能采用协议,因此它们在此上下文中无关紧要。)

因此,如果符合协议的对象需要存储在弱属性中,那么该协议必须是仅类协议。

当该协议的要求定义的行为假定或要求符合类型具有引用语义而不是值语义时,使用仅类协议。


当我们将receiverVC分配给nil时;

不会有内存泄漏。

  • 弱引用允许引用对象变为 nil(当引用对象被释放时,这会自动发生)
  • 根据上述规则,引用对象/变量必须是可选的

参考

https://medium.com/macoclock/delegate-retain-cycle-in-swift-4d9c813d0544

https://newbedev.com/how-can-i-make-a-weak-protocol-reference-in-pure-swift-without-objc

以上是关于翻译: Swift 中的委托保留周期 如何在“纯”Swift(没有@objc)中进行弱协议引用的主要内容,如果未能解决你的问题,请参考以下文章

翻译: 如何使用 Xcode 的内存图调试器检测 iOS 内存泄漏并保留周期

目标 C - 因保留周期而丢失

如何在 Swift 中的框架内创建委托/回调? [复制]

swift 关闭保留周期

如何在目标 c 中引用 swift app 委托

如何在目标 C 和 swift Viewcontroller 中使用委托