如何将协议转换为 NSObject<Protocol> 以访问受限扩展接口?

How to cast Protocol to NSObject<Protocol> to access constrained extension interface?

问题参考Swift3。 从版本 4 开始,您终于可以像这样将对象转换为 Type<Protocol>

someObject as (Type & Protocol)

我有一个协议和多个继承自它的类型。

A, B, C, D: CKEntity (pseudocode)

对于该协议,我有一个对象继承自 NSObject 的情况:

分机号是:

extension CKEntity where Self : NSObject {

static func method() {
    ...
}

适用于多种情况。

我有一个函数采用 Class(Type) 实现 CKEntity。

如果也是NSObject,我需要检查是否符合大小写。 如果是,调用适当的函数。

我想要完成的原型:

func validateSync(ofType type: CKEntity.Type) {
    let a = (type as NSObject.Type & CKEntity.Type).self

    a.method() // Compilation error: Type 'Any' has no member 'method'
}

无效。

问题是:

如何将类型 (Protocol.Type) 转换为 NSObject.Type(不是实例)以满足扩展约束?


场景(回顾):

  1. A 的扩展名,其中 A 是 B

  2. A可以是B

  3. 需要将 A 转换为 A:B 并达到受约束的 A&B 接口。

解决方案找到了,有点。

问题在于,在扩展 NSObject 时,最好求助于扩展 NSObjectProtocol 而不是 NSObject 本身(即使您将要扩展后者)。

原因是 NSObject 本身不是协议,这给 Swift 复合协议检查带来了困难。 NSObjectProtocol,另一方面,自然被任何NSObject派生的对象所继承,是一个协议,是一个key

因此,如果可能的话(这是可能的,如果它是关于 NSObject 的),我们应该在这里重构事物以将类型向下转换为 多个协议

分机修改如下:

extension NSObjectProtocol where Self : CKEntity {
     static func method() {
         // ...
     }
}

支票是:

 if let extendedType = type as? NSObjectProtocol & CKEntity.Type {
     extendedType.self.method()
 }

而且有效!

可能会遇到的缺点是 NSObjectProtocol 不包含 KVC 方法,因此您需要像这样转换对象以获得 KVC 接口:

extension NSObjectProtocol where Self : CKEntity {

    static var staticVar : String {
        return (Self.self as! NSObject.Type).className()
    }


    var publicVar : String! {
        return (self as! NSObject).value(forKey: "Key") as! String
    }
}