2016-02-13 80 views
0

我试图通过协议将功能添加到NSManagedObject。我添加了一个可以正常工作的默认实现,但只要我试图用协议扩展我的子类,它就会告诉我它的一部分没有实现,尽管我添加了默认实现。Swift中协议扩展的默认实现不起作用

任何人有我在做什么想法错误?

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

帮助非常赞赏。

回答

4

我们将使用更多的按比例缩小的例子(见下文)对这里有什么不顺心线索。然而,关键的“错误”是Case不能使用objectWithId()的默认实现... where T: NSManagedObject, I: AnyObject;因为类型Int不符合类型约束AnyObject。后者用来表示类类型的实例,而Int类型。

AnyObject可以表示任何类类型的实例。

Any可以在所有代表任何类型的实例,包括功能类型。

Language Guide - Type casting

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


FooT默认的扩展名:■符合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") 
    } 
} 

同样是,但是,并不是真正用于扩展FooT:■符合AnyObject,如Int不符合类型普通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访问默认实现objectWithId()... where T: NSManagedObject, I: AnyObject,因为NSNumber是类类型,它符合到AnyObject


最后,从以上所不需要用于实现在一个协议blueprinted方法关键字override实施例说明(例如,在你的例子entityName()方法上文)。 Case的扩展是一个协议扩展(通过实现蓝图类型和方法符合),并且与超类(在这种情况下,您可能想要重写超类方法)对子类化Case没有真正的可比性。

+1

这是对的我得出了同样的结论,我用NSNumber替换Int并且它工作。 Any的问题是,它不符合VArgType,因此我不能将它用作谓词的参数。感谢您的好解释! –

+0

@GeorgKitz乐于帮助! – dfri

+0

@GeorgKitz那么,你能否简单地将你的泛型类型限制在我所在的位置:CVarArgType? –

0

我找到了解决问题的办法。我认为这是typealias T,这是不编译的原因。实际上这不是真的,这是我对AnyObject说的,有趣的是Int不是AnyObject。我不得不将Int更改为NSNumber