何时在Swift中使用`protocol`和`protocol:class`?

问题描述 投票:40回答:5

我已经设置了一个协议,可以将一些信息发送回以前的VC。

我这样定义它:

protocol FilterViewControllerDelegate: class  {
    func didSearch(Parameters:[String: String]?)
}

但是使用时有什么区别:

protocol FilterViewControllerDelegate  {
        func didSearch(Parameters:[String: String]?)
    }

以及我何时应使用: class协议?

swift swift-protocols
5个回答
50
投票

Swift 4版本

[AnyObject已添加到这样的协议定义中

protocol FilterViewControllerDelegate: AnyObject  {
    func didSearch(parameters:[String: String]?)
}

意味着只有一个类才能遵守该协议。

给定这个

protocol FilterViewControllerDelegate: AnyObject  {
    func didSearch(parameters:[String: String]?)
}

您将能够写出这个

class Foo: FilterViewControllerDelegate {
    func didSearch(parameters:[String: String]?) { }
}

但是NOT

struct Foo: FilterViewControllerDelegate {
    func didSearch(parameters:[String: String]?) { }
}

Swift 3版本

[:class已添加到这样的协议定义中

protocol FilterViewControllerDelegate: class  {
    func didSearch(Parameters:[String: String]?)
}

意味着只有一个类才能遵守该协议。

给定这个

protocol FilterViewControllerDelegate: class  {
    func didSearch(Parameters:[String: String]?)
}

您将能够写出这个

class Foo: FilterViewControllerDelegate {
    func didSearch(Parameters:[String: String]?) { }
}

但是NOT

struct Foo: FilterViewControllerDelegate {
    func didSearch(Parameters:[String: String]?) { }
}

24
投票

还有另一件事,用class关键字标记协议。

这就是您的协议声明:

Swift 4语法(根据docs

protocol FilterViewControllerDelegate: AnyObject  {
    func didSearch(parameters:[String: String]?)
}

Swift 4之前的语法

protocol FilterViewControllerDelegate: class  {
    func didSearch(parameters:[String: String]?)
}

例如,假设您要创建一个DetailVC,它具有一个委托属性:

class DetailViewController: UISomeViewController {
    weak var delegate: FilterViewControllerDelegate
}

如果您不使用class关键字标记该协议,那么您也将无法将该delegate属性标记为weak一个。

为什么?

很简单-仅基于类的属性可以具有弱关系。如果您想避免参考循环,那就可以这样做😁


9
投票

Swift 5.1,Xcode 11语法:

protocol FilterViewControllerDelegate: AnyObject {
       func didSearch(Parameters:[String: String]?)
}

该协议只能被类采用。

回答您的第一个问题-

但是使用时有什么区别:

与此处的区别:

protocol FilterViewControllerDelegate  {
        func didSearch(Parameters:[String: String]?)
}

是该协议可以采用值类型,例如枚举和结构。

回答第二个问题-

我何时应该使用:class protocal?

当您应该使用类协议时,我想从委托模式描述下一个示例:假设您有委托协议。

protocol PopupDelegate: AnyObject {
    func popupValueSelected(value: String)
}

并且在另一个类中要创建属性

var delegate: PopupDelegate?

但这具有很强的参考意义,可能使您遇到内存泄漏的问题。解决内存泄漏的一种方法是使委托属性变弱。在我们不让我们的协议仅可用于类申请之前,Swift认为我们可以将协议也应用于值类型。

weak var delegate: PopupDelegate?

如果您尝试将您的代表声明为弱者,您将看到下一个错误:

'weak'var仅适用于类和类绑定的协议类型,不是'PopupDelegate'

但是我们不能将弱应用于值类型。因此,我们需要将协议限制为引用类型,因此swift知道其为引用类型。为了使您可以将此委托声明为弱,您需要限制协议仅由类使用:

protocol PopupDelegate: AnyObject {
    func popupValueSelected(value: String)
}

5
投票

这意味着您定义的协议只能由类采用,而不能由结构或枚举采用。

来自Official Swift book

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // class-only protocol definition goes here } 

在上面的示例中,SomeClassOnlyProtocol仅可用于类类型。它是编写结构或枚举定义时发生的编译时错误试图采用SomeClassOnlyProtocol。


1
投票

Swift 3.2更新:

要声明仅类的协议,现在写:

protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
    // class-only protocol definition goes here
}

代替

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // class-only protocol definition goes here
}

第二个片段目前似乎仍然有效。参考:https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html

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