2015-07-10 39 views
0

我目前正在Swift中的iOS项目上工作,我试图使用Swift泛型和协议在NSManagedObjectContext之上构建某种扩展。我已经执行类似下面的一些方法:NSManagedObjectContext扩展中的泛型函数中的奇怪的Swift行为

extension NSManagedObjectContext { 

    func objectWhere<T: NSManagedObject>(entityClass: T.Type, predicate: NSPredicate) -> T? { 
     let entityName = NSStringFromClass(entityClass) 
     let request = NSFetchRequest(entityName: entityName) 

     //...fetch object code here 

     return result?.first 
    } 
} 

这种方法效果很好,但trickyness是当我想要实现的UPSERT。基本上我做的是创造一个协议,就像这样:

protocol Updatable { 
    static func primaryKeyJSON() -> String 

    static func primaryKey() -> String 

    func populate(JSON: [NSObject: AnyObject], context: NSManagedObjectContext) 

    func update(JSON: [NSObject: AnyObject], context: NSManagedObjectContext) 
} 

接下来我要做的事情就是延长我的NSManagedObject子类本协议中的一个。在我目前的项目中,例如我有一个名为Person的类来实现这个协议。这个协议应该允许我创造在同一的NSManagedObjectContext扩展这样的UPSERT方法:但是

func upsert<T where T: NSManagedObject, T: Updatable>(entityClass: T.Type, JSON: [NSObject: AnyObject]) -> T? { 
    return nil 
} 

的问题是,每当我把这种方法Xcode中给出了一个错误说:“式结束后的预计会员名称或构造函数调用名称”。

c.upsert(Person, JSON: ["test": "sometest"]) 

最奇怪的是,这个问题的第一种方法工作得很好。另外,当我删除JSON:参数形式的upsert函数时,它不会给出该错误并编译并运行得很好。

有人能告诉我发生了什么事吗?

+1

我无法解释为什么,但如果你写的upsert(Person.self ...我会编译,可能值得一个雷达 –

+0

嗯,确实编译,奇怪的是,所有其他方法没有工作,但我会检查是否可以提交雷达。 – Arthur

回答

0

我不认为一个类/结构或协议是返回隐式的类型。然而,当你的函数只有一个参数T.Type时,会发生这种情况。

这里是Apples Swift Library说:

您可以使用后缀自我表达访问类型的值。例如,SomeClass.self返回SomeClass本身,而不是SomeClass的实例。并且SomeProtocol.self返回SomeProtocol本身,而不是在运行时符合SomeProtocol类型的实例。

这可能会改变,我的手指也会越过。但是现在,如果函数中有多个参数,则必须输入self后缀。

protocol SomeProtocol {} 

func someFunc1<T: SomeProtocol>(_: T.Type) -> String { "\(T.self)" } 
func someFunc2<T: SomeProtocol>(_: T.Type, someInt: Int) -> String { "\(T.self) + \(someInt)"} 

extension Int : SomeProtocol {} 

someFunc1(Int) // returns "Swift.Int" <--- this is a bug 
someFunc1(Int.self) // returns "Swift.Int" 

someFunc2(Int, someInt: 42) // Expected memeber name or constructer call after type name 
someFunc2(Int.self, someInt: 42) // returns "Swift.Int + 42" 

Btw。我想你可以修改你的代码有点像这样:

func objectWhere<T: NSManagedObject>(_: T.Type, predicate: NSPredicate) -> T? { 
    let entityName = "\(T.self)" 
    /* ... */ 
} 

UPDATE:这个问题就是一个bug,读here