我目前正在研究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:参数时,它不会给出该错误并编译并完全运行。
有人可以告诉我发生了什么事吗?
答案 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: