Swift documentation说明以下有关协议:
只有在协议标记为@objc属性时才能检查协议一致性,如上面的HasArea协议所示 . 此属性指示协议应该暴露给Objective-C代码,并在使用Swift with Cocoa和Objective-C中进行了描述 . 即使您没有与Objective-C进行互操作,如果您希望能够检查协议一致性,也需要使用@objc属性标记协议 . 另请注意,@ objc协议只能由类采用,而不能由结构或枚举采用 . 如果将协议标记为@objc以检查一致性,则只能将该协议应用于类类型 .
和
如果您的协议标有@objc属性,则只能指定可选协议要求 . 即使您没有与Objective-C进行互操作,如果要指定可选要求,也需要使用@objc属性标记协议 . 另请注意,@ objc协议只能由类采用,而不能由结构或枚举采用 . 如果将协议标记为@objc以指定可选要求,则只能将该协议应用于类类型 .
为什么不能检查纯Swift协议(非 @objc
)的一致性 . 为什么他们没有可选要求?任何人都可以猜出潜在的语言设计原因吗?
我希望在未来的某些未确定(可能很远)的时间,Apple将慢慢重新实现并用纯粹在Swift中编程的库替换Cocoa和CocoaTouch . 那时,如果我们不想避免使用任何与Obj-C相关的东西,我们是否应该避免在代码中使用可选的协议要求和协议检查一致性?
如果是这样的话,'s Swift'在不使用 @objc
的情况下实现类似模式的惯用方法是什么? (例如,具有可选方法的代表 . )
例如,这个简单的用例不能用非 @objc
协议实现( Printable
, DebugPrintable
和 Streamable
非 @objc
:
import UIKit
let firstName = "John"
let lastName = "Appleseed"
let age = 33
let height = 1.74
let values: [Any] = [firstName, lastName, age, height]
let stringifiedValues = [String]()
for value in values
{
if let pritanbleValue = value as? Printable
{
stringifiedValues.append(value.description)
}
else if let debugPrintableValue = value as? DebugPrintable
{
stringifiedValues.append(value.debugDescription)
}
else if let streamableValue = value as? Streamable
{
var string = ""
streamableValue.writeTo(&string)
stringifiedValues.append(string)
}
// etc.
else
{
stringifiedValues.append("[NoStringRepresentation]")
}
}
2 回答
Swift可能没有包含足够的运行时类型信息来检查协议一致性 . 协议实际上只是编译时的事情,而ObjC在构建产品中包含额外的表,这些表对于运行程序来说并不是绝对必要的,以便确定一致性 . 由于@objc必须将类/协议转换为ObjC理解的内容,因此使用此属性声明的对象会获得额外的元数据以及其他适配器数据结构,因此ObjC不会注意到它们不是真正的ObjC .
Apple在ObjC中的建议一直是检查单个方法的存在,而不是查看类或协议,以允许鸭子类型并允许使用代理对象 . 我的猜测是,这就是为什么Swift的设计者认为在默认情况下省略协议运行时数据是可以的,以鼓励正确检测类的功能 .
至于如何使用它:对于协议的情况,你显然应该使用
?
运算符(它检查对象是否存在以及它是否实现给定的方法) . 在这种情况下,我不会_256107_是一个ObjC课程,你可以调用foo.respondsToSelector("doFoo:")
.苹果员工jckarter在Apple Developer Forums' thread上说了以下内容: