如何在'纯'Swift中创建弱协议引用(不带@objc)

本文翻译自: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 used unowned ) and always use var (not let ) so that the optional can be set to nil 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 the weak 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 the class keyword, but AnyObject 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关键字和闭包发生的强引用循环。

Related 有关


#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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值