Swift在通过参数传递泛型类型时无法推断出具体的泛型类型。

4 浏览
0 Comments

Swift在通过参数传递泛型类型时无法推断出具体的泛型类型。

我正在为核心数据编写一个通用的包装类。\n以下是一些基本类型。没什么特别的。\ntypealias CoreDataSuccessLoad = (_: NSManagedObject) -> Void\ntypealias CoreDataFailureLoad = (_: CoreDataResponseError?) -> Void\ntypealias ID = String\nenum CoreDataResult {\n case success(Value)\n case failure(Error)\n}\nenum CoreDataResponseError : Error {\n typealias Minute = Int\n typealias Key = String\n case idDoesNotExist\n case keyDoesNotExist(key: Key)\n case fetch(entityName: String)\n}\n\n我已经在协议中抽象了我的核心数据写入。如果您对我试图实现的抽象有任何评论,我将不胜感激。\n然而,在扩展中,我遇到了以下错误:\n

无法将类型为“NSFetchRequest”的值转换为预期的参数类型“NSFetchRequest<_>”

\n不确定如何解决它。我尝试了改变代码的各种变体,但没有成功...\nprotocol CoreDataWriteManagerProtocol {\n associatedtype ManagedObject : NSManagedObject\n var persistentContainer : NSPersistentContainer {get}\n var idName : String {get}\n func loadFromDB(storableClass : ManagedObject.Type, id: ID) throws -> CoreDataResult\n func update(storableClass : ManagedObject.Type, id: ID, fields: [String : Any]) throws\n func fetch(request: NSFetchRequest, from context: NSManagedObjectContext)\n init(persistentContainer : NSPersistentContainer)\n}\nextension CoreDataWriteManagerProtocol {\n private func loadFromDB(storableClass : ManagedObject.Type, id: ID) -> CoreDataResult{\n let predicate = NSPredicate(format: \"%@ == %@\", idName, id)\n let fetchRequest : NSFetchRequest = storableClass.fetchRequest()\n fetchRequest.predicate = predicate\n // 下面这行代码出现错误!\n return fetch(request: fetchRequest, from: persistentContainer.viewContext) \n }\n func fetch(request: NSFetchRequest, from context: NSManagedObjectContext) -> CoreDataResult{\n guard let results = try? context.fetch(request) else {\n return .failure(CoreDataResponseError.fetch(entityName: request.entityName ?? \"空实体名称\")) // @TODO 不确定是否传递了entityName。\n }\n if let result = results.first {\n return .success(result)\n }else{\n return .failure(CoreDataResponseError.idDoesNotExist)\n }\n }\n}\n\n此外,如果我将以下行:\nlet fetchRequest : NSFetchRequest = storableClass.fetchRequest()\n\n更改为:\nlet fetchRequest : NSFetchRequest = storableClass.fetchRequest()\n\n我会得到以下错误:\n

使用未声明的类型“storableClass”

\n我的直觉告诉我,编译器无法映射“类型参数”即它无法理解`storableClass`实际上是一个类型。相反,它只能映射泛型参数或实际类型。因此,这样做不起作用。\n编辑:\n我使用Vadian的静态方法,并编写了以下代码:\nprivate func create(_ entityName: String, json : [String : Any]) throws -> ManagedObject {\n guard let entityDescription = NSEntityDescription.entity(forEntityName: entityName, in: Self.persistentContainer.viewContext) else {\n print(\"entityName: \\(entityName)不存在!\")\n throw CoreDataError.entityNotDeclared(name: entityName)\n }\n let _ = entityDescription.relationships(forDestination: NSEntityDescription.entity(forEntityName: \"CountryEntity\", in: Self.persistentContainer.viewContext)!)\n let relationshipsByName = entityDescription.relationshipsByName\n let propertiesByName = entityDescription.propertiesByName\n guard let managedObj = NSEntityDescription.insertNewObject(forEntityName: entityName, into: Self.persistentContainer.viewContext) as? ManagedObject else {\n throw CoreDataError.entityNotDeclared(name: entityName)\n }\n for (propertyName,_) in propertiesByName {\n if let value = json[propertyName] {\n managedObj.setValue(value, forKey: propertyName)\n }\n }\n // 设置所有关系\n guard !relationshipsByName.isEmpty else {\n return managedObj\n }\n for (relationshipName, _ ) in relationshipsByName {\n if let object = json[relationshipName], let objectDict = object as? [String : Any] {\n let entity = try create(relationshipName, json: objectDict)\n managedObj.setValue(entity, forKey: relationshipName)\n }\n }\n return managedObj\n}\n\n但其中一部分不是通用的,因为我使用了`as? ManagedObject`进行了强制转换。基本上它不符合Swift的风格。Vadian如此描述:\nguard let managedObj = NSEntityDescription.insertNewObject(forEntityName: entityName, into: Self.persistentContainer.viewContext) as? ManagedObject else {\n throw CoreDataError.entityNotDeclared(name: entityName)\n}\n\n有没有什么办法解决这个问题?

0
0 Comments

Swift无法推断泛型类型,当泛型类型通过参数传递时,会出现这个问题。出现这个问题的原因是,NSManagedObject.fetchRequest()的返回类型是NSFetchRequest<NSFetchRequestResult>,它是非泛型的。你需要更新fetch函数的定义来解决这个问题。另外,协议扩展中默认实现的函数签名实际上与协议定义中的函数签名不匹配,所以这些也需要更新。

你还需要改变fetch(request:,from:)的实现,因为NSManagedObjectContext.fetch()返回的值类型是[Any],所以你需要将其转换为[ManagedObject]以匹配你自己的fetch方法的类型签名。

解决方法是将fetch(request: NSFetchRequest<NSFetchRequestResult>, from: NSManagedObjectContext)方法中的try? context.fetch(request)用括号括起来,以防止try?应用于整个表达式,包括类型转换,从而导致返回值是一个嵌套的Optional,这是不希望的。

此外,由于Objective-C没有泛型的概念,你需要在使用现有的CoreData方法时进行类型转换。因此,在获取返回值时,你需要将其从Any类型转换为[ManagedObject]类型,可以使用as? [ManagedObject]进行转换。

总之,这个问题的出现是由于你在使用现有的CoreData方法时存在误解,这些方法都不是泛型的,都是用Objective-C编写的,但你期望它们被导入为泛型到Swift中。这是不可能的。

0
0 Comments

问题:当泛型类型通过参数传递时,Swift无法推断出泛型类型。

原因:在传递泛型类型时,Swift无法自动推断出泛型类型,导致编译器无法确定返回的具体类型。

解决方法:使用静态方法来调用loadFromDB和fetch方法,并且在NSManagedObject子类上调用这些方法。这样做的好处是无需进行任何进一步的类型转换即可返回相关类型。另外,将错误抛出改为使用throw关键字。在成功时返回对象,在失败时抛出错误。此外,还可以添加一个static func predicate(for id : ID)方法。对于insertNewObject方法,可以直接返回插入的对象,而无需进行错误处理。

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) 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(entityName: entityName)

request.predicate = predicate

return try fetch(request: request)

}

static func fetch(request: NSFetchRequest) 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

}

}

使用这个方法的示例代码如下:

extension TripEntity : CoreDataWriteManagerProtocol {}

let trip = TripEntity.loadFromDB(predicate: myPredicate)

trip.passengerName = "John"

trip.cost = 13

TripEntity.persistentContainer.viewContext.save()

以上是关于Swift无法推断泛型类型的原因和解决方法的内容。

0