Swift协议错误: 'weak'不能应用于非类类型

102

协议和类限定协议有什么区别,在Swift中应该使用哪一个?

protocol A : class { ... }

protocol A { ... }
尝试在未将协议定义为: class时,添加一个weak委托时,会出现错误。
protocol A { ... }

weak var delegate: A

出现错误:

'weak' 不能应用于非类类型

或者

'weak' 必须不应用于非类约束的 'A'; 考虑添加一个带有类约束的协议一致性

5个回答

215

Swift >= 4:

protocol A : AnyObject { ... }

Swift < 4:

protocol A : class { ... }

定义了一个"仅类可遵循协议":只有类类型(而不是结构体或枚举)可以采用此协议。

弱引用仅适用于引用类型。类是引用类型,结构体和枚举是值类型。(闭包也是引用类型,但闭包不能采用协议,所以在这种情况下无关紧要。)

因此,如果遵循该协议的对象需要存储在弱属性中,则该协议必须是仅类可遵循的协议。

这里是另一个需要仅类可遵循协议的示例:

protocol A { 
    var name : String { get set }
}

func foo(a : A) {
    a.name = "bar" // error: cannot assign to property: 'a' is a 'let' constant
}

这段代码无法编译,因为对于结构体和枚举类型的实例,a.name = "bar" 是对 a 的改变。如果你将协议定义为:

protocol A : class { 
    var name : String { get set }
}

如果编译器知道a是一个类类型的实例,那么它就知道a是对象存储的引用,而a.name = "bar"会修改被引用的对象,但不会修改a本身。

因此,通常情况下,您需要定义一个仅限于类的协议,如果您需要采用该协议的类型为引用类型而不是值类型。


在你的代码示例中,你说'a'是一个'let'常量。我有点困惑。是什么让a在这里成为一个常量? - Suragch
@Suragch:函数参数中的 a,例如 func foo(a : A),默认情况下是常量 - Martin R
因此,如果您的协议定义了一个弱属性,这是不正确的。协议只定义了“get”和“get set”,而没有定义“weak”或“strong”属性。所以应该这样写:“因此,如果符合协议的对象需要存储在弱属性中…” - Nicolas Miari

23

如果您正在使用 Swift 4 或更高版本,请使用 AnyObject

protocol A : AnyObject { ... }

之前使用class定义泛型约束协议会出现警告和建议更正:

使用'class'关键字来定义一个类约束类型的协议已经被弃用,应该使用'AnyObject'代替。

将'class'替换为'AnyObject'


9

您可以使协议派生自任何类类型,例如NSObject或AnyObject:

protocol TopNewsTableDelegate : AnyObject {
    func topNewsTableDidLoadedStories()
}

2
protocol CustomProtocolName : NSObjectProtocol {
  // ...
}

2
最初的回答
或者你可以像这样输入

@objc protocol A { ... }

最初的回答:如果您想要创建一个弱委托引用,那么您可以这样做。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接