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

问题描述 投票:526回答:6

weak引用似乎在Swift中不起作用,除非protocol被声明为@objc,我不想在纯粹的Swift应用程序中使用。

此代码给出了编译错误(weak不能应用于非类类型MyClassDelegate):

class MyClass {
  weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate {
}

我需要在协议前加上@objc,然后才有效。

问题:什么是完成weak delegate的'纯'斯威夫特方式?

swift delegates swift-protocols
6个回答
973
投票

您需要将协议类型声明为class

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

class SomeClass {
    weak var delegate: ProtocolNameDelegate?
}

我的理解是使用class,你保证这个协议只能用于类,而不能用于其他东西,如枚举或结构。


247
投票

Supplemental Answer

我一直很困惑代表们是否应该是弱者。最近我学到了更多关于代表以及何时使用弱引用的知识,所以让我在这里为了未来的观众添加一些补充点。

  • 使用weak关键字的目的是避免使用strong reference cycles(保留周期)。当两个类实例具有相互强引用时,就会发生强引用循环。他们的引用计数永远不会变为零,因此它们永远不会被释放。
  • 如果委托是一个类,你只需要使用weak。 Swift结构和枚举是值类型(它们的值在创建新实例时被复制),而不是引用类型,因此它们不会产生强引用循环。
  • weak引用总是可选的(否则你会使用unowned)并且总是使用var(而不是let),以便在解除分配时可选的设置为nil
  • 父类自然应该强烈引用其子类,因此不使用weak关键字。但是,当一个孩子想要引用它的父级时,它应该通过使用weak关键字使其成为弱引用。
  • 当您想要引用您不拥有的类时,应该使用weak,而不仅仅是引用其父级的子类。当两个非分层类需要相互引用时,选择一个为弱。你选择的那个取决于具体情况。有关详细信息,请参阅this question的答案。
  • 作为一般规则,代理应标记为weak,因为大多数代表都引用了他们不拥有的类。当孩子使用委托与父母沟通时,这肯定是正确的。对代表使用弱引用是documentation推荐的内容。 (但也见this。)
  • 协议可以用于reference types(类)和value types(结构,枚举)。因此,在可能需要使委托变弱的情况下,您必须使其成为仅对象协议。这样做的方法是将AnyObject添加到协议的继承列表中。 (过去你使用class关键字,但AnyObject is preferred now。) protocol MyClassDelegate: AnyObject { // ... } class SomeClass { weak var delegate: MyClassDelegate? }

Further Study

阅读以下文章有助于我更好地理解这一点。他们还讨论了unowned关键字等相关问题以及闭包发生的强引用周期。

Related


32
投票

AnyObject是在Swift中使用弱引用的官方方式。

class MyClass {
    weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate: AnyObject {
}

来自Apple:

为了防止强引用循环,应将委托声明为弱引用。有关弱引用的详细信息,请参阅类实例之间的强引用循环。将协议标记为仅限类将稍后允许您声明委托必须使用弱引用。您通过继承AnyObject将协议标记为仅仅类,如“仅类协议”中所述。

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276


9
投票

更新:看起来手册已更新,我所指的示例已被删除。请参阅上面@ @ flainez的回复编辑。

原文:即使你没有与Obj-C互操作,使用@objc也是正确的方法。它确保您的协议应用于类而不是枚举或结构。请参阅手册中的“检查协议一致性”。


-2
投票

protocol must be subClass of AnyObject, class

示例如下

    protocol NameOfProtocol: class {
   // member of protocol
    }
   class ClassName: UIViewController {
      weak var delegate: NameOfProtocol? 
    }

-9
投票

Apple使用“NSObjectProtocol”而不是“class”。

public protocol UIScrollViewDelegate : NSObjectProtocol {
   ...
}

这也适用于我并删除了我在尝试实现自己的委托模式时看到的错误。

© www.soinside.com 2019 - 2024. All rights reserved.