NSManagedObjectContext扩展中泛型函数中的奇怪Swift行为

时间:2015-07-10 09:43:08

标签: ios swift generics

我目前正在研究Swift中的iOS项目,我正在尝试使用Swift泛型和协议在NSManagedObjectContext上构建某种扩展。我已经实现了一些类似下面的方法:

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
   }
}

这种方法运行正常,但是当我想实现一个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"])
然而,最奇怪的是,这个问题的第一种方法完全正常。此外,当我从upsert函数中删除JSON:参数时,它不会给出该错误并编译并完全运行。

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

1 个答案:

答案 0 :(得分: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"

顺便说一下。我想你可以像这样修改你的代码:

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

更新:问题只是一个错误,请阅读here