我发现Xcode 8中Core Data编辑器中的新代码生成功能文档有些不够充分。
这是一个“如果用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
}
}
entity()
在同一位置被定义。当编译器从NSFetchRequest(entityName:)
接收获取请求时,它似乎不会对let语句进行类型检查。在这种情况下,它对实体没有任何了解,因为初始化程序仅采用字符串。如果您明确地将其他语句强制转换为as! NSFetchRequest<Self>
,它也可以正常工作。但是,通常不需要这样做。这总是有效的:let fetchRequest: NSFetchRequest<MyEntity> = MyEntity.fetchRequest()
。也许,这只是一个怪癖,不重要。 - salo.dm