我在Xcode 8的核心数据编辑器中找到有关新codegen功能的文档有点稀疏。
这是"在Objective-C中,我愿意......"有点问题。
我试图声明一个有两种方法的协议:
@property (strong, readonly) NSNumber *serverId;
+ (instancetype)objectWithServerId:(NSNumber*)serverId inContext:(NSManagedObjectContext*)moc;
在Objective-C中,我将使用mogenerator声明生成的基类应该是" MyBaseClass"。
在那个基类中我可以实现一次该类方法。在Core Data编辑器中,我只需要确保我的实体具有该属性。在人类可读的'文件,我会声明它符合该协议,并且因为它继承自该基类(基本上是抽象的),所以它可以调用上面列出的类方法。
我认为通过强打字,这可能是不可能的。我已经使它工作,但我创建的每个子类(使用Xcode生成的扩展)必须实现此方法,而我更喜欢将该方法编写为通用。
在Swift中,我将该属性添加到实体(没有父级,因此它是NSManagedObject的子类),并且这样做了:
protocol RemoteObjectProtocol {
var serverId: Int64 {get}
static func object<T: NSManagedObject>(WithServerId serverId: Int64, context: NSManagedObjectContext!) -> T?
}
import CoreData
@objc(TestObject)
class TestObject: NSManagedObject {
}
extension TestObject: RemoteObjectProtocol {
// by nature of it being in the generated core data model, we just need to declare its conformance.
static func object<T: NSManagedObject>(WithServerId serverId: Int64, context: NSManagedObjectContext!) -> T? {
// IF YOU FIND A BETTER WAY TO SOLVE THIS, PLEASE DO!
// I would have loved to use a baseclass RemoteObject: NSManagedObject, where you can just implement this
// Method. But there was no way for it to play nicely with the CoreData Editor
// in addition, the convenience method generated by Xcode .fetchRequest() only seems to work outside of this extension.
// Extensions can't make use of other extensions
// So we create the fetch request 'by hand'
let fetchRequest = NSFetchRequest<TestObject>(entityName: "TestObject")
fetchRequest.predicate = NSPredicate(format: "serverId == %i", serverId)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "serverId", ascending: true)]
fetchRequest.fetchLimit = 1
do {
let fetchedObjects = try context.fetch(fetchRequest)
return fetchedObjects.first as! T?
} catch {
log.warning("Failed to fetch object with serverId:\(serverId) error:\(error)")
}
return nil
}
}
答案 0 :(得分:2)
Codegen类可以符合协议。并且,Swift协议可以提供任何函数的默认实现。
所以,至少在理论上,实现你在Swift中所做的比在Objective-C中更简单。但是,正确使用语法可能有点棘手。
主要问题如下:
@objc
作为协议声明的前言,以便它可以与CoreData和NSManagedObject一起使用因此,对于协议,以下代码应该这样做:
import CoreData
@objc protocol RemoteObject {
var serverId: Int64 { get }
}
extension RemoteObject where Self: NSManagedObject {
static func objectWithServerId(_ serverId: Int64, context: NSManagedObjectContext) -> Self? {
let fetchRequest: NSFetchRequest<Self> = NSFetchRequest(entityName: Self.entity().name!)
let predicate = NSPredicate(format: "serverId == %d", serverId)
let descriptor = NSSortDescriptor(key: #keyPath(RemoteObject.serverId), ascending: true)
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = [descriptor]
fetchRequest.fetchLimit = 1
do {
let results = try context.fetch(fetchRequest)
return results.first
} catch {
print("Failed to fetch object with serverId:\(serverId) error:\(error)")
}
return nil
}
}
并且,正如您所指出的,每个实体都已具有serverId
属性。因此,您只需要声明它符合协议:
extension MyCoreDataEntity: RemoteObject {
}
请注意,由于某种原因,编译器会拒绝更简单的行:
let fetchRequest: NSFetchRequest<Self> = Self.fetchRequest()
这个更简单的行会产生以下错误:Cannot convert value of type 'NSFetchRequest<NSFetchRequestResult>' to specified type 'NSFetchRequest<Self>'
。但是,出于某种原因,上述解决方法并没有。
非常欢迎任何关于这种情况发生的想法。