我正在为核心数据编写通用包装类。
这是我的一些基本类型。没什么特别的。
typealias CoreDataSuccessLoad = (_: NSManagedObject) -> Void typealias CoreDataFailureLoad = (_: CoreDataResponseError?) -> Void typealias ID = String enum CoreDataResult<Value> { case success(Value) case failure(Error) } enum CoreDataResponseError : Error { typealias Minute = Int typealias Key = String case idDoesNotExist case keyDoesNotExist(key: Key) case fetch(entityName: String) }
我已经将我的coredata写在协议中抽象化了。如果您让我知道您对我要提出的抽象的意见,我将不胜感激。但是在扩展中,我遇到了以下错误:
无法将类型“ NSFetchRequest”的值转换为预期的参数类型“ NSFetchRequest <_>”
不确定我该如何解决。我尝试了各种更改代码的尝试,但未成功……
protocol CoreDataWriteManagerProtocol { associatedtype ManagedObject : NSManagedObject var persistentContainer : NSPersistentContainer {get} var idName : String {get} func loadFromDB(storableClass : ManagedObject.Type, id: ID) throws -> CoreDataResult<ManagedObject> func update(storableClass : ManagedObject.Type, id: ID, fields: [String : Any]) throws func fetch(request: NSFetchRequest<ManagedObject>, from context: NSManagedObjectContext) init(persistentContainer : NSPersistentContainer) } extension CoreDataWriteManagerProtocol { private func loadFromDB(storableClass : ManagedObject.Type, id: ID) -> CoreDataResult<ManagedObject>{ let predicate = NSPredicate(format: "%@ == %@", idName, id) let fetchRequest : NSFetchRequest = storableClass.fetchRequest() fetchRequest.predicate = predicate // ERROR at below line! return fetch(request: fetchRequest, from: persistentContainer.viewContext) } func fetch<ManagedObject: NSManagedObject>(request: NSFetchRequest<ManagedObject>, from context: NSManagedObjectContext) -> CoreDataResult<ManagedObject>{ guard let results = try? context.fetch(request) else { return .failure(CoreDataResponseError.fetch(entityName: request.entityName ?? "Empty Entity Name")) // @TODO not sure if entityName gets passed or not. } if let result = results.first { return .success(result) }else{ return .failure(CoreDataResponseError.idDoesNotExist) } } }
另外,如果我更改行:
let fetchRequest : NSFetchRequest = storableClass.fetchRequest()
至:
let fetchRequest : NSFetchRequest<storableClass> = storableClass.fetchRequest()
我收到以下错误:
使用未声明的类型’storableClass’`
我的直觉告诉我,编译器无法映射“类型的参数”,即它不理解storableClass实际上是类型。相反,它只能映射泛型参数或实际类型。因此,这是行不通的。
storableClass
编辑:
我使用静态方法Vadian并编写了此代码:
private func create(_ entityName: String, json : [String : Any]) throws -> ManagedObject { guard let entityDescription = NSEntityDescription.entity(forEntityName: entityName, in: Self.persistentContainer.viewContext) else { print("entityName: \(entityName) doesn't exist!") throw CoreDataError.entityNotDeclared(name: entityName) } let _ = entityDescription.relationships(forDestination: NSEntityDescription.entity(forEntityName: "CountryEntity", in: Self.persistentContainer.viewContext)!) let relationshipsByName = entityDescription.relationshipsByName let propertiesByName = entityDescription.propertiesByName guard let managedObj = NSEntityDescription.insertNewObject(forEntityName: entityName, into: Self.persistentContainer.viewContext) as? ManagedObject else { throw CoreDataError.entityNotDeclared(name: entityName) } for (propertyName,_) in propertiesByName { if let value = json[propertyName] { managedObj.setValue(value, forKey: propertyName) } } // set all the relationships guard !relationshipsByName.isEmpty else { return managedObj } for (relationshipName, _ ) in relationshipsByName { if let object = json[relationshipName], let objectDict = object as? [String : Any] { let entity = try create(relationshipName, json: objectDict) managedObj.setValue(entity, forKey: relationshipName) } } return managedObj }
但是下面的部分不是通用的,因为我使用进行了转换as? ManagedObject。基本上,这不是Vadian所说的Swifty:
as? ManagedObject
guard let managedObj = NSEntityDescription.insertNewObject(forEntityName: entityName, into: Self.persistentContainer.viewContext) as? ManagedObject else { throw CoreDataError.entityNotDeclared(name: entityName) }
有什么办法解决吗?
我的建议有些不同。它使用 静态 方法
在子类上调用loadFromDB和。好处是,始终返回关联的类型,而无需任何其他类型强制转换。fetch``NSManagedObject
loadFromDB
fetch``NSManagedObject
另一个变化是throw错误。由于Core Data API广泛依赖于throw错误,因此我建议删除CoreDataResult<Value>。所有错误均已通过。成功返回对象,失败返回错误。
throw
CoreDataResult<Value>
我省略了id相关的代码和update方法。您可以添加一个static func predicate(for id : ID)
id
update
static func predicate(for id : ID)
protocol CoreDataWriteManagerProtocol { associatedtype ManagedObject : NSManagedObject = Self static var persistentContainer : NSPersistentContainer { get } static var entityName : String { get } static func loadFromDB(predicate: NSPredicate?) throws -> ManagedObject static func fetch(request: NSFetchRequest<ManagedObject>) throws -> ManagedObject static func insertNewObject() -> ManagedObject } extension CoreDataWriteManagerProtocol where Self : NSManagedObject { static var persistentContainer : NSPersistentContainer { return (UIApplication.delegate as! AppDelegate).persistentContainer } static var entityName : String { return String(describing:self) } static func loadFromDB(predicate: NSPredicate?) throws -> ManagedObject { let request = NSFetchRequest<ManagedObject>(entityName: entityName) request.predicate = predicate return try fetch(request: request) } static func fetch(request: NSFetchRequest<ManagedObject>) throws -> ManagedObject { guard let results = try? persistentContainer.viewContext.fetch(request) else { throw CoreDataResponseError.fetch(entityName: entityName) } if let result = results.first { return result } else { throw CoreDataResponseError.idDoesNotExist } } static func insertNewObject() -> ManagedObject { return NSEntityDescription.insertNewObject(forEntityName: entityName, into: persistentContainer.viewContext) as! ManagedObject } }