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

时间:2014-06-05 17:16:55

标签: swift delegates swift-protocols

weak引用似乎不适用于Swift,除非protocol被声明为@objc,我不想在纯粹的Swift应用中使用。< / p>

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

class MyClass {
  weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate {
}

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

问题:什么是纯粹的&#39;快速完成weak delegate

的方式

7 个答案:

答案 0 :(得分:964)

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

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

class SomeClass {
    weak var delegate: ProtocolNameDelegate?
}

我的理解是使用class,您可以保证此协议仅用于类,而不用于枚举或结构等其他内容。

答案 1 :(得分:244)

补充答案

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

  • 使用weak关键字的目的是避免强引用周期(保留周期)。当两个类实例具有相互强引用时,就会发生强引用循环。他们的引用计数永远不会变为零,因此它们永远不会被释放。

  • 如果委托是一个类,您只需要使用weak。 Swift结构和枚举是值类型(它们的值在创建新实例时被复制),而不是引用类型,因此它们不会进行强大的引用循环。

  • weak引用始终是可选的(否则您将使用unowned)并始终使用var(而非let),以便将可选项设置为<{1}}何时被解除分配。

  • 父类自然应该对其子类具有强引用,因此不使用nil关键字。但是,如果孩子想要引用其父级,则应使用weak关键字将其作为弱引用。

  • 如果您想要引用您不拥有的类,而不仅仅是引用其父级的子级,则应使用
  • weak。当两个非分层类需要相互引用时,选择一个为弱。你选择的那个取决于具体情况。有关详情,请参阅this question的答案。

  • 作为一般规则,代理应标记为weak ,因为大多数代理都引用了他们不拥有的类。当孩子使用委托与父母沟通时,这肯定是正确的。但是,仍然有some situations代表可以而且应该使用强引用。

  • 协议可用于reference types(类)和value types(结构,枚举)。因此,在您需要使委托变弱的情况下,您必须将weak关键字添加到协议中,以便它知道它仅用于引用类型。

    class

进一步研究

阅读以下文章有助于我更好地理解这一点。他们还讨论了相关问题,例如protocol MyClassDelegate: class { // ... } class SomeClass { weak var delegate: MyClassDelegate? } 关键字以及闭包发生的强引用周期。

相关

答案 2 :(得分:30)

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

答案 3 :(得分:9)

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

<强>原始 即使您没有与Obj-C互操作,使用@objc也是正确的方法。它确保您的协议应用于类而不是枚举或结构。请参阅&#34;检查协议一致性&#34;在手册中。

答案 4 :(得分:0)

弱限定符仅适用于引用对象。除非您在协议中添加 @objcAnyObjectclass 限定符,否则符合协议的对象可能不是引用对象。

因此您需要使用这些限定符(推荐使用 AnyObject,因为预计 class 将被弃用。)

顺便说一下,即使在“纯 Swift”应用程序中,有时也需要将 @objc 添加到您的类和属性中。它与您的开发语言无关。它会导致编译器以与 Objective-C 运行时兼容的方式构建您的代码,这是某些操作系统接口(例如目标/操作和旧式键路径)所必需的

答案 5 :(得分:-2)

协议必须是AnyObject的子类,类

以下示例

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

答案 6 :(得分:-9)

Apple使用&#34; NSObjectProtocol&#34;而不是&#34; class&#34;。

public protocol UIScrollViewDelegate : NSObjectProtocol {
   ...
}

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