从 AnyObject 扩展的协议和只有类的协议有什么区别?

这两份声明

protocol SomeProtocol : AnyObject {
}

还有这份声明

protocol SomeProtocol : class {
}

似乎使得只有类可以遵守这个协议(即协议的实例是对象的引用) ,并且没有其他效果。

他们之间有什么区别吗?应该优先选择其中一个吗?如果不是,为什么有两种方法可以做同样的事情?

我使用的是最新发布的 Xcode 6.3.1。

21263 次浏览

我之前说错了。@马丁真的应该回答这个问题,因为是他纠正了我,并提供了正确的信息。

真的的不同之处在于,带有类限定符的协议只能应用于类,而不能应用于结构或枚举。

马丁,为什么你不回答,观察员可以接受你的回答?

AnyObject是所有类都隐式遵循的协议(来源)。所以我认为没有区别: 您可以使用其中任何一个来要求类约束。

关于答案 https://forums.swift.org/t/class-only-protocols-class-vs-anyobject/11507/4,这个答案是不推荐的。这些词现在是一样的。

不赞成

更新: 经过与 我们的力量协商,这两个定义是 假设是等价的,与 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派生协议,那么这个示例将立即失败:

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'
}

因此,看起来 classAnyObject的一个更为保守的版本,当您只关心引用语义而不关心动态成员查找或 Objective-C 桥接时,应该使用它。

协议快速编程语言指南,在 只有类的协议部分。它只提到了 AnyObject,但没有提到 class

通过将 AnyObject 协议添加到协议的继承列表,可以将协议采用限制为类类型(而不是结构或枚举)。

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

基于这个原因,我建议在新代码或新项目中使用 AnyObject而不是 class。除此之外,我看不出他们之间有什么明显的区别。

如果您在 Xcode 9中打开 class的帮助(alt-click) ,例如 protocol P: class {},您将得到 typealias AnyObject

因此,无论您将协议约束为 class还是 AnyObject,编译的代码(在 Swift 4中)都是相同的。

尽管如此,还存在 风格未来的选择的问题ーー未来的 Swift 版本可能希望以某种微妙的方式区别对待 classAnyObject,即使目前情况并非如此。

(编辑: 这最终发生在 Swift 5.4/Xcode 12.5中。)

这个问题是由官方的 Swift 开发者(Slava _ Pestov)在 快速论坛上回答的。以下是摘要:

  • 您应该使用 AnyObject (protocol SomeProtocol: AnyObject)。

  • AnyObjectclass是等价的,没有区别。

  • class最终将被弃用。

从2021年开始,Xcode 12.5,Big Sur OS:

苹果不赞成使用 class

使用 AnyObject代替。

编码愉快。

Deprecated