2015-07-10 72 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