Swift中无@objc的协议弱引用:完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

如何在纯Swift中(无@objc)创建协议弱引用?完整指南及示例

\n\n

想象一下:您正在用Swift编写应用程序,使用Delegate模式,突然——砰!——您的对象无法释放,内存不断增长,应用程序开始卡顿。熟悉吗?很可能您遇到了retain cycle(强引用循环)。经典问题是:委托持有对拥有者的强引用,而拥有者也持有对委托的强引用。首先想到的解决方案是让协议引用变为弱引用(weak)。但Swift会带来一个惊喜:如果协议没有标记@objc,您不能直接声明weak var delegate: MyProtocol。编译器会报错。为什么?更重要的是——如何解决?

\n\n

在本文中,我们将探讨如何在纯Swift中实现无@objc的weak protocol reference。您将了解为什么这是一个问题,有哪些解决方案,以及如何编写优雅、安全且无内存泄漏的代码。开始吧!

\n\n

为什么weak protocol reference不能“开箱即用”?

\n\n

让我们回顾一下Swift中weak的工作原理。弱引用(weak)只能用于引用类型(类)。为什么?因为只有类对象通过ARC(自动引用计数)进行内存管理。结构体(struct)和枚举(enum)是值类型,它们会被复制,因此“弱引用”的概念对它们没有意义。

\n\n

当您编写:

\n
weak var delegate: MyProtocol?
\n

编译器不知道MyProtocol将由类、结构体还是枚举实现。万一它是结构体呢?那么weak就无法应用。因此出现错误:“'weak' may only be applied to class and class-bound protocol types”。

\n\n

以前(在Objective-C中),所有协议默认只能由类实现,因此weak可以工作。在纯Swift中,协议是通用的——这很好,但也增加了复杂性。

\n\n

解决方案#1:class-bound protocol(仅类协议)

\n\n

最简单且最常用的方法是明确指定协议只能由类实现。为此,在协议声明中使用关键字AnyObject(或已弃用的class)。

\n\n

示例:

\n
protocol MyDelegate: AnyObject {\n    func didSomething()\n}\n\nclass ViewController {\n    weak var delegate: MyDelegate?\n\n    func doSomething() {\n        delegate?.didSomething()\n    }\n}\n\nclass SomeClass: MyDelegate {\n    func didSomething() {\n        print("委托已触发!")\n    }\n}\n\n// 使用\nlet vc = ViewController()\nlet some = SomeClass()\nvc.delegate = some\nvc.doSomething() // 输出:"委托已触发!"
\n\n

一切正常。MyDelegate现在只能由类(class)实现,而weak是合法的。这是Apple推荐的委托方法。

\n\n

为什么这很好?

\n
    \n
  • 简单且可读性强。
  • \n
  • 完全支持ARC。
  • \n
  • 无需@objc。
  • \n
\n\n

缺点?

\n
    \n
  • 您失去了用结构体实现协议的可能性。但对于委托来说,这通常不是必需的。
  • \n
\n\n

解决方案#2:使用泛型包装器(适用于特殊情况)

\n\n

如果您必须允许协议既可由类实现也可由结构体实现,同时又想要弱引用怎么办?这种情况很少见,但有可能。例如,您正在编写一个库,用户既可以传递类也可以传递结构体。这时可以使用包装器。

\n\n

思路:创建一个结构体,它存储对实现协议对象的弱引用。对于类——使用we

博客

书籍推荐