Swift 中协议扩展的默认实现不起作用

Default implementation of protocol extension in Swift not working

我正在尝试通过协议向 NSManagedObject 添加功能。我添加了一个工作正常的默认实现,但是当我尝试使用协议扩展我的子类时,它告诉我它的某些部分没有实现,即使我添加了默认实现。

有人知道我做错了什么吗?

class Case: NSManagedObject {

}

protocol ObjectByIdFetchable {
    typealias T
    typealias I
    static var idName: String { get }
    static func entityName() -> String
    static func objectWithId(ids:[I], context: NSManagedObjectContext) -> [T]
}

extension ObjectByIdFetchable where T: NSManagedObject, I: AnyObject {

    static func objectWithId(ids:[I], context: NSManagedObjectContext) -> [T] {
       let r = NSFetchRequest(entityName: self.entityName())
       r.predicate = NSPredicate(format: "%K IN %@", idName, ids)

       return context.typedFetchRequest(r)
   }
}

extension Case: ObjectByIdFetchable {

   typealias T = Case
   typealias I = Int

   class var idName: String {
       return "id"
   }

   override class func entityName() -> String {
       return "Case"
   }
}

我得到的错误是Type Case doesn't conform to protocol ObjectByIdFetchable

非常感谢帮助。

我们将使用更缩小的示例(如下)来阐明此处出现的问题。然而,关键 "error" 是 Case 不能为 ... where T: NSManagedObject, I: AnyObject 使用 objectWithId() 的默认实现;因为类型 Int 不符合类型约束 AnyObject。后者用于表示 class 类型的实例,而 Intvalue 类型。

AnyObject can represent an instance of any class type.

Any can represent an instance of any type at all, including function types.

来自Language Guide - Type casting.

随后,Case 无法访问蓝图 objectWithId() 方法的任何实现,因此不符合协议 ObjectByIdFetchable.


默认扩展 FooT:s 符合 Any 有效,因为 Int 符合 Any:

protocol Foo {
    typealias T
    static func bar()
    static func baz()
}

extension Foo where T: Any {
    static func bar() { print ("bar") }
}

class Case : Foo {
    typealias T = Int

    class func baz() {
        print("baz")
    }
}

但是,将 Foo 扩展到 T 则不符合 AnyObject,因为 Int 不符合 [=75] =]-型一般AnyObject:

protocol Foo {
    typealias T
    static func bar()
    static func baz()
}

/* This will not be usable by Case below */
extension Foo where T: AnyObject {
    static func bar() { print ("bar") }
}

/* Hence, Case does not conform to Foo, as it contains no
   implementation for the blueprinted method bar()    */
class Case : Foo {
    typealias T = Int

    class func baz() {
        print("baz")
    }
}

编辑添加:请注意,如果您更改(如您在自己的答案中发布的那样)

typealias T = Int

进入

typealias T = NSNumber

那么自然地 Case 可以访问 ... where T: NSManagedObject, I: AnyObjectobjectWithId() 默认实现,因为 NSNumber 是 class 类型,符合 AnyObject.


最后,请注意上面的示例,关键字 override 不需要实现协议中蓝图的方法(例如,上面示例中的 entityName() 方法)。 Case 的扩展是一个协议扩展(通过实现蓝图类型和方法来符合 ObjectByIdFetchable),并不能真正与 super[= 的 subclassing Case 相提并论75=](在这种情况下,您可能希望重写 superclass 方法)。

我找到了问题的解决方案。我认为这是类型别名 T 这是不编译的原因。这其实不是真的,是我对 AnyObject 说的,有趣的是 Int 不是 AnyObject。我不得不将 Int 更改为 NSNumber