【发布时间】:2015-07-22 11:55:59
【问题描述】:
这两个声明
protocol SomeProtocol : AnyObject {
}
还有这个声明
protocol SomeProtocol : class {
}
似乎只有类才能符合这个协议(即协议的实例是对对象的引用),并且没有其他效果。
它们之间有什么区别吗?应该优先选择一个吗?如果不是,为什么有两种方法可以做同样的事情?
我使用的是最新发布的 Xcode 6.3.1。
【问题讨论】:
这两个声明
protocol SomeProtocol : AnyObject {
}
还有这个声明
protocol SomeProtocol : class {
}
似乎只有类才能符合这个协议(即协议的实例是对对象的引用),并且没有其他效果。
它们之间有什么区别吗?应该优先选择一个吗?如果不是,为什么有两种方法可以做同样的事情?
我使用的是最新发布的 Xcode 6.3.1。
【问题讨论】:
官方 Swift 开发人员 (Slava_Pestov) 在Swift forums 上回答了这个问题。总结如下:
你应该使用AnyObject (protocol SomeProtocol: AnyObject)。
AnyObject 和 class 是等价的。没有区别。
class 最终将被弃用。
【讨论】:
关于答案https://forums.swift.org/t/class-only-protocols-class-vs-anyobject/11507/4,此答案已弃用。这些词现在都一样了。
已弃用
更新:在咨询the powers that be 之后,这两个定义应该是等效的,AnyObject 被用作替代品,而 class 正在完成。未来后者将取代前者,但就目前而言,它们确实存在一些细微差别。
区别在于@objc 声明的语义。使用AnyObject,期望符合的类可能是也可能不是正确的Objective-C 对象,但语言无论如何都会这样对待它们(因为有时您会丢失静态调度)。从中得出的结论是,您可以对待 AnyObject 等人。协议约束作为请求 @objc 成员函数的一种方式,如 STL 中 AnyObject 文档中的示例所示:
import Foundation
class C {
@objc func getCValue() -> Int { return 42 }
}
// If x has a method @objc getValue()->Int, call it and
// return the result. Otherwise, return nil.
func getCValue1(x: AnyObject) -> Int? {
if let f: ()->Int = x.getCValue { // <===
return f()
}
return nil
}
// A more idiomatic implementation using "optional chaining"
func getCValue2(x: AnyObject) -> Int? {
return x.getCValue?() // <===
}
// An implementation that assumes the required method is present
func getCValue3(x: AnyObject) -> Int { // <===
return x.getCValue() // x.getCValue is implicitly unwrapped. // <===
}
如果您将其更改为 class-deriving 协议,相同的示例会立即失效:
import Foundation
protocol SomeClass : class {}
class C : SomeClass {
@objc func getCValue() -> Int { return 42 }
}
// If x has a method @objc getValue()->Int, call it and
// return the result. Otherwise, return nil.
func getCValue1(x: SomeClass) -> Int? {
if let f: ()->Int = x.getCValue { // <=== SomeClass has no member 'getCValue'
return f()
}
return nil
}
// A more idiomatic implementation using "optional chaining"
func getCValue2(x: SomeClass) -> Int? {
return x.getCValue?() // <=== SomeClass has no member 'getCValue'
}
// An implementation that assumes the required method is present
func getCValue3(x: SomeClass) -> Int { // <===
return x.getCValue() // <=== SomeClass has no member 'getCValue'
}
所以看起来class 是AnyObject 的更保守版本,当您只关心引用语义而不关心动态成员查找或Objective-C 桥接时应该使用它。
【讨论】:
AnyObject 与定义为protocol MyClassProtocol : class {} 的MyClassProtocol 之间的区别现在很清楚了。我仍然缺少的是protocol MyObjectProtocol : AnyObject {} 和protocol MyClassProtocol : class {} 之间的区别。
protocol Protocol : AnyObject {} 不能与protocol Protocol : class {} 互换。
protocol SomeProtocol : AnyObject { } 和 protocol SomeProtocol : class { } 之间根本没有 no 区别,但您声称 "... 目前,它们确实提出了一些小问题差异”。请原谅我的固执,但我仍然看不到您的代码如何证明这种差异。
: class 的用法,但我也很想知道上面提到的您的 cmets 中的区别。从那以后,您是否成功地发现了上述两者之间的任何具体差异(即“......现在,它们确实存在一些细微的差异”)?请原谅我的固执。谢谢。
class 更为保守——我怀疑是因为它的实现不完整。以后不会了。
在Swift programming language guide for protocols 的Class-Only Protocols 部分下。它只提到了AnyObject,但没有提到class。
您可以通过将 AnyObject 协议添加到协议的继承列表中来将协议采用限制为类类型(而不是结构或枚举)。
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
// class-only protocol definition goes here
}
出于这个原因,我建议在新代码或新项目中使用AnyObject 而不是class。除此之外,我看不出它们之间有任何明显的区别。
【讨论】:
AnyObject 是所有类都隐式遵循的协议 (source)。所以我想说没有区别:你可以使用任何一个来要求类约束。
【讨论】:
如果您在 Xcode 9 中为 class 打开帮助(alt-click)在一行中,例如 protocol P: class {},您将获得 typealias AnyObject。
因此,无论您将协议限制为 class 还是 AnyObject,编译的代码(在 Swift 4 中)都是相同的。
也就是说,还有 style 和 future options 的问题——未来的 Swift 版本可能希望在某些细微的地方区别对待 class 和 AnyObject方式,即使现在不是这样。
(编辑:这最终发生在 Swift 5.4/Xcode 12.5 中。)
【讨论】:
Redundant constraint 'Self' : 'AnyObject' 并且需要删除 AnyObject 引用或将其替换为 NSObjectProtocol
我之前说错了。 @MartinR 应该真正回答这个问题,因为他是纠正我并提供正确信息的人。
真正的区别在于带有类限定符的协议只能应用于类,而不是结构或枚举。
Martin,你为什么不回答,OP 可以接受你的回答?
【讨论】:
protocol SomeProtocol : AnyObject { } ; struct Foo : SomeProtocol { } 给出编译器错误non-class type 'Foo' cannot conform to class protocol 'SomeProtocol'。 (我感觉其实没有区别,但我无法证明。)
protocol SomeProtocol: Any。让我想知道类限定符的意义是什么。我(错误地)假设它将协议限制为类,而不是类的实例,但文档清楚地说明了其他情况。
AnyObject 完全相同,因为只有对象可以符合这一点,在预期 AnyObject 的地方既不能使用枚举也不能使用结构。真正的区别在于AnyObject 可以是 Swift 类或 Obj-C 对象(或其他符合该协议的对象),但只有 Swift 类可以符合 class。