AnyObject如何符合NSObjectProtocol?

JAL*_*JAL 9 nsobject swift swift-protocols anyobject

这个问题的灵感来自mz2关于检查对象类型失败并且"不是类型"错误的问题的答案.

考虑一个空的Swift类:

class MyClass { }
Run Code Online (Sandbox Code Playgroud)

试图NSObjectProtocol在此类的实例上调用任何方法将导致编译时错误:

let obj = MyClass()
obj.isKindOfClass(MyClass.self) // Error: Value of type 'MyClass' has no member 'isKindOfClass'
Run Code Online (Sandbox Code Playgroud)

但是,如果我将实例转换为AnyObject,我的对象现在符合NSObjectProtocol,我可以调用协议定义的实例方法:

let obj: AnyObject = MyClass()
obj.isKindOfClass(MyClass.self) // true
obj.conformsToProtocol(NSObjectProtocol) // true
obj.isKindOfClass(NSObject.self) // false
Run Code Online (Sandbox Code Playgroud)

我的对象不继承NSObject,但仍然符合NSObjectProtocol.怎么AnyObject符合NSObjectProtocol

mat*_*att 5

在Cocoa/Objective-C世界中,AnyObject是id.将此对象强制转换为AnyObject后,您可以向其发送任何已知的Objective-C消息,例如isKindOfClassconformsToProtocol.现在,当你说isKindOfClass或者conformsToProtocol,你不再是斯威夫特世界了; 你正在和Objective-C谈论Cocoa.那么想想Objective-C如何看待这个对象.Objective-C世界中的所有类都来自某个基类; 像MyClass这样没有基础的类是不可能的.Objective-C世界中的每个基类都符合NSObject协议(Swift称之为NSObjectProtocol); 这是基类的原因(或从基类中下降)!因此,为了使它进入Objective-C世界,Swift将MyClass呈现为一个特殊的桥接基类SwiftObject,它确实符合NSObjectProtocol(正如你在这里看到的那样:https://github.com/apple/swift/blob /master/stdlib/public/runtime/SwiftObject.mm).

  • 疯狂。在这种情况下,`isKindOfClass` 是否实际上是作为动态调度的消息发送的,即使类本身不是 Objective-C 可见的类型,并且它自己的方法不使用基于消息的调度? (2认同)

mz2*_*mz2 5

如果我基于matt的答案正确地理解这一点,那么当Swift/Objective-C互操作可用时,这是有效的,因为实际上Swift类类型最终继承了SwiftObject当编译Objective-C互操作时,实际涉及Objective-C类(实现SwiftObject,SwiftObject.mm当使用Objective-C interop时,编译为Objective-C++.因此,将一个Swift类类型的对象作为AnyObject类型"泄露"该信息.

Swift源代码中查看实现中的一些相关位,文件swift/stdlib/public/runtime/SwiftObject.mm:

#if SWIFT_OBJC_INTEROP

// …

@interface SwiftObject<NSObject> {
   SwiftObject_s header;
}

// …

@implementation SwiftObject

// …

- (BOOL)isKindOfClass:(Class)someClass {
  for (auto isa = _swift_getClassOfAllocated(self); isa != nullptr;
       isa = _swift_getSuperclass(isa))
    if (isa == (const ClassMetadata*) someClass)
      return YES;

  return NO;
}

// …

// #endif
Run Code Online (Sandbox Code Playgroud)

正如预测的那样,在Linux中使用Swift 3(根据我的理解,没有Objective-C运行时作为Swift运行时和基础实现的一部分可用吗?)来自这个问题的示例代码和之前的问题和答案启发了这个问题因以下错误编译错误而失败:

ERROR […] value of type 'AnyObject' has no member 'isKindOfClass'
Run Code Online (Sandbox Code Playgroud)