当通过参数传递泛型类型时,Swift无法推断泛型类型

我正在为核心数据编写通用包装类。

这是我的一些基本类型。没什么特别的。

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实际上是类型。相反,它只能映射泛型参数或实际类型。因此,这是行不通的。

我使用静态方法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:

guard let managedObj = NSEntityDescription.insertNewObject(forEntityName: entityName, into: Self.persistentContainer.viewContext) as? ManagedObject else {

throw CoreDataError.entityNotDeclared(name: entityName)

}

有什么办法解决吗?

回答:

我的建议有些不同。它使用 方法

在子类上调用loadFromDB和。好处是,始终返回关联的类型,而无需任何其他类型强制转换。fetch``NSManagedObject

另一个变化是throw错误。由于Core Data

API广泛依赖于throw错误,因此我建议删除CoreDataResult<Value>。所有错误均已通过。成功返回对象,失败返回错误。

我省略了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

}

}

以上是 当通过参数传递泛型类型时,Swift无法推断泛型类型 的全部内容, 来源链接: utcz.com/qa/407898.html

回到顶部