本文翻译自:How can I make a weak protocol reference in 'pure' Swift (without @objc)
weak
references don't seem to work in Swift unless a protocol
is declared as @objc
, which I don't want in a pure Swift app. weak
引用似乎在Swift中不起作用,除非将protocol
声明为@objc
,我不想在纯Swift应用程序中使用它。
This code gives a compile error ( weak
cannot be applied to non-class type MyClassDelegate
): 此代码给出了编译错误( weak
不能应用于非类型MyClassDelegate
):
class MyClass {
weak var delegate: MyClassDelegate?
}
protocol MyClassDelegate {
}
I need to prefix the protocol with @objc
, then it works. 我需要在协议前加上@objc
,然后@objc
。
Question: What is the 'pure' Swift way to accomplish a weak
delegate
? 问题:完成weak
delegate
的'纯'Swift方法是什么?
#1楼
参考:https://stackoom.com/question/1cykC/如何在-纯-Swift中创建弱协议引用-不带-objc
#2楼
Update: It looks like the manual has been updated and the example I was referring to has been removed. 更新:看起来手册已更新,我所指的示例已被删除。 See the edit to @flainez's answer above. 请参阅上面@ @ flainez的回复编辑。
Original: Using @objc is the right way to do it even if you're not interoperating with Obj-C. 原文:即使你没有与Obj-C互操作,使用@objc也是正确的方法。 It ensures that your protocol is being applied to a class and not an enum or struct. 它确保您的协议应用于类而不是枚举或结构。 See "Checking for Protocol Conformance" in the manual. 请参阅手册中的“检查协议一致性”。
#3楼
You need to declare the type of the protocol as class
. 您需要将协议的类型声明为class
。
protocol ProtocolNameDelegate: class {
// Protocol stuff goes here
}
class SomeClass {
weak var delegate: ProtocolNameDelegate?
}
My understanding is that using class
, you guarantee that this protocol will be used only on classes and no other stuff like enums or structs. 我的理解是使用class
,你保证这个协议只能用在类上,而不能用于其他东西,比如枚举或结构。
#4楼
Supplemental Answer 补充答案
I was always confused about whether delegates should be weak or not. 我一直很困惑代表们是否应该是弱者。 Recently I've learned more about delegates and when to use weak references, so let me add some supplemental points here for the sake of future viewers. 最近我学到了更多关于代表以及何时使用弱引用的知识,所以让我在这里为了未来的观众添加一些补充点。
The purpose of using the
weak
keyword is to avoid strong reference cycles (retain cycles). 使用weak
关键字的目的是避免强引用循环 (保留循环)。 Strong reference cycles happen when two class instances have strong references to each other. 当两个类实例具有相互强引用时,就会发生强引用循环。 Their reference counts never go to zero so they never get deallocated. 他们的引用计数永远不会变为零,因此它们永远不会被释放。You only need to use
weak
if the delegate is a class. 如果委托是一个类,你只需要使用weak
。 Swift structs and enums are value types (their values are copied when a new instance is made), not reference types, so they don't make strong reference cycles. Swift结构和枚举是值类型(它们的值在创建新实例时被复制),而不是引用类型,因此它们不会产生强引用循环。weak
references are always optional (otherwise you would usedunowned
) and always usevar
(notlet
) so that the optional can be set tonil
when it is deallocated.weak
引用总是可选的(否则你会使用unowned
)和总是使用var
(未let
),使得可选可以设置为nil
,当它被释放。A parent class should naturally have a strong reference to its child classes and thus not use the
weak
keyword. 父类自然应该对其子类具有强引用,因此不使用weak
关键字。 When a child wants a reference to its parent, though, it should make it a weak reference by using theweak
keyword. 但是,当一个孩子想要引用它的父元素时,它应该通过使用weak
关键字使它成为弱引用。weak
should be used when you want a reference to a class that you don't own, not just for a child referencing its parent. 当您想要引用您不拥有的类时,应该使用weak
,而不仅仅是引用其父级的子类。 When two non-hierarchical classes need to reference each other, choose one to be weak. 当两个非分层类需要相互引用时,选择一个为弱。 The one you choose depends on the situation. 你选择的那个取决于具体情况。 See the answers to this question for more on this. 有关此问题的更多信息,请参阅此问题的答案。As a general rule, delegates should be marked as
weak
because most delegates are referencing classes that they do not own. 作为一般规则,代理应标记为weak
因为大多数代表都引用了他们不拥有的类。 This is definitely true when a child is using a delegate to communicate with a parent. 当孩子使用委托与父母沟通时,这肯定是正确的。 Using a weak reference for the delegate is what the documentation recommends. 对代表使用弱引用是文档建议的内容。 (But see this , too.) (但也要看到这一点。)Protocols can be used for both reference types (classes) and value types (structs, enums). 协议可用于引用类型 (类)和值类型 (结构,枚举)。 So in the likely case that you need to make a delegate weak, you have to make it an object-only protocol. 因此,在可能需要使委托变弱的情况下,您必须使其成为仅对象协议。 The way to do that is to add
AnyObject
to the protocol's inheritance list. 这样做的方法是将AnyObject
添加到协议的继承列表中。 (In the past you did this using theclass
keyword, butAnyObject
is preferred now .) (在过去,您使用class
关键字执行此操作,但现在首选AnyObject
。)protocol MyClassDelegate: AnyObject { // ... } class SomeClass { weak var delegate: MyClassDelegate? }
Further Study 进一步研究
Reading the following articles is what helped me to understand this much better. 阅读以下文章有助于我更好地理解这一点。 They also discuss related issues like the unowned
keyword and the strong reference cycles that happen with closures. 他们还讨论了相关问题,如unowned
关键字和闭包发生的强引用循环。
- Delegate documentation 委托文件
- Swift documentation: Automatic Reference Counting Swift文档: 自动引用计数
- "Weak, Strong, Unowned, Oh My!" “弱,强,无主,哦,我的!” - A Guide to References in Swift - Swift中的参考指南
- Strong, Weak, and Unowned – Sorting out ARC and Swift 强,弱和无主 - 整理ARC和Swift
Related 有关
- How to make delegates in Swift 如何在Swift中创建委托
- iOS: How To Make Weak Delegates In Swift iOS:如何在Swift中使弱代表
- Swift delegation - when to use weak pointer on delegate Swift委托 - 何时在委托上使用弱指针
#5楼
Apple uses "NSObjectProtocol" instead of "class". Apple使用“NSObjectProtocol”而不是“class”。
public protocol UIScrollViewDelegate : NSObjectProtocol {
...
}
This also works for me and removed the errors I was seeing when trying to implement my own delegate pattern. 这也适用于我并删除了我在尝试实现自己的委托模式时看到的错误。
#6楼
AnyObject
is the official way to use a weak reference in Swift. AnyObject
是在Swift中使用弱引用的官方方式。
class MyClass {
weak var delegate: MyClassDelegate?
}
protocol MyClassDelegate: AnyObject {
}
From Apple: 来自Apple:
To prevent strong reference cycles, delegates should be declared as weak references. 为了防止强引用循环,应将委托声明为弱引用。 For more information about weak references, see Strong Reference Cycles Between Class Instances. 有关弱引用的详细信息,请参阅类实例之间的强引用循环。 Marking the protocol as class-only will later allow you to declare that the delegate must use a weak reference. 将协议标记为仅限类将稍后允许您声明委托必须使用弱引用。 You mark a protocol as being class-only by inheriting from AnyObject , as discussed in Class-Only Protocols. 您通过继承AnyObject将协议标记为仅仅类,如“仅类协议”中所述。
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276 https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276