弱委托和 class 协议

weak Delegate and class protocol

我一直在使用协议和委托方法在调用 dismissViewControll 后将数据传回之前的 VC。以下是我通常的做法,因为大多数教程都不是这样写的

protocol someVCDelegate {
    func somefunction()
}

var delegate: someVCDelegate!

但是,我遇到了这种 class/weak 编写方法。

protocol someVCDelegate : class {
    func somefunction()
}

weak var delegate: someVCDelegate!

我了解 weak 与 ARC 相关联并避免了保留循环。但是,我不确定在我所有的情况下我什么时候需要它,而不是做弱委托工作查找(VC 确实 deinit)。在什么样的情况下我需要弱委托?还有,为什么是“!”在弱之后,通常是“?”后弱对吗?

为什么它很弱:弱引用是一种引用,它不会对其引用的实例保持强控制,因此不会阻止 ARC 处理引用的实例。此行为可防止引用成为强引用循环的一部分。或者简单地说,您通过将 类 之间的一些关系定义为弱引用或无主引用而不是强引用来解决强引用循环。

而且是“!”在 weak 之后,因为它是隐式解包的。它会有价值。

有时从程序的结构中可以清楚地看出,在首次设置值之后,可选值将始终具有值。在这些情况下,消除每次访问时检查和解包可选值的需要很有用,因为可以安全地假设它始终具有值。

你说:

However, I am not sure when I would need it as in all my cases, not doing weak delegate works

当你有可能形成强引用循环时,你只需要弱 protocol-delegate 模式,即强引用的循环系列。例如,考虑:

  • 一个object("parent")有一个属性("child"),即parent有一个强引用 child;

  • child有一个delegate属性;和

  • 你设置child的delegate引用parentobject.

在这种情况下,委托必须是 weak 引用,否则您将拥有强大的引用循环。

请注意,这是一个简单的示例,有时强引用链可能会相当复杂。例如,考虑一个具有委托 属性 的 UIView 子类。潜在的强引用周期可能会相当长,从视图控制器到它的根 view,通过一系列子视图的子视图,一直到 UIViewdelegate可能会引用回视图控制器。这也将导致一个强大的引用循环,因此我们倾向于为那个 delegate 使用 weak 引用。

但是,当您使用 protocol-delegate 模式在视图控制器之间传递数据时,这通常不是问题(视图控制器包含除外),因为呈现视图控制器不拥有呈现的视图控制器。视图控制器层次结构通常维护对视图控制器的强引用。因此,当您关闭呈现的视图控制器时,它会被释放并解决潜在的强引用循环。

通常,我们会本能地使用 weak protocol-delegate 模式(仅仅是因为它完全可以防止强引用循环的发生)。但有时你会使用强引用。最常见的强引用模式是 NSURLSession,其中 delegate 是强引用。正如 documentation for init(configuration:delegate:delegateQueue:) 警告我们:

The session object keeps a strong reference to the delegate until your app exits or explicitly invalidates the session. If you do not invalidate the session by calling the invalidateAndCancel() or finishTasksAndInvalidate() method, your app leaks memory until it exits.

虽然这看起来很矛盾,但这种强引用模式的优点是会话知道它可以安全地调用它的委托方法而不用担心 object 被释放。 (顺便说一句,NSURLSession 的这种强委托行为很少出现,因为我们经常使用完成处理程序方法而根本不使用委托方法,而当我们使用委托方法时,我们经常有一些 object 除了视图控制器作为会话的委托。)

简而言之,您真的必须评估每种情况,并确定我们本能地倾向于使用弱引用是否更好,或者您是否遇到其中一种情况,您的协议更适合使用强引用。