我在一个类中有一个静态函数,该函数采用必须符合可解码的泛型类型,但是当我调用此函数时,我收到以下错误:"表达式类型不明确,没有更多上下文"。Tour 类(这是我传递给函数的类型(符合 Decodable 并从 CoreDataModel 类继承。
当我调用 CoreDataModel.create 时,这发生在 DashboardNetworkAdapter 中的新 Xcode 12.0 Beta 上(我为该类共享的代码片段的第 7 行(。
编辑最小可重现示例:
仪表板网络适配器:
class DashboardNetworkAdapter {
// MARK: - GET
public func syncTours(page: Int, completion: @escaping(Bool, Error, Bool) -> Void) {
if let path = Bundle.main.path(forResource: "Tours", ofType: "json") {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
CoreDataModel.create(Array<Tour>.self, from: data) { success, error in
completion(success, error, false)
}
} catch let error {
completion(false, error, false)
}
}
}
}
核心数据模型:
public class CoreDataModel: NSManagedObject {
// MARK: - Variables
@NSManaged public var id: Int64
@NSManaged public var createdAt: Date?
@NSManaged public var updatedAt: Date?
// MARK: - CRUD
static func create<T>(_ type: T.Type, from data: Data, completion: @escaping (Bool, Error?) -> Void) where T : Decodable {
DataCoordinator.performBackgroundTask { context in
do {
let _ = try DataDecoder(context: context).decode(type, from: data, completion: {
completion(true, nil)
})
} catch let error {
completion(false, error)
}
}
}
}
旅游:
@objc(Tour)
class Tour: CoreDataModel, Decodable {
// MARK: - Variables
@NSManaged public var name: String?
@NSManaged public var image: URL?
@NSManaged public var owned: Bool
@NSManaged public var price: Double
// MARK: - Coding Keys
enum CodingKeys: String, CodingKey {
case id = "id"
case name = "name"
case image = "image"
case owned = "owned"
case price = "price"
case updatedAt = "updated_at"
case createdAt = "created_at"
}
// MARK: - Initializer
required convenience init(from decoder: Decoder) throws {
guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("Cannot find decoding context")}
self.init(context: context)
let topLevel = try decoder.container(keyedBy: PaginatedResponseCodingKeys.self)
let values = try topLevel.nestedContainer(keyedBy: CodingKeys.self, forKey: .data)
let id = try values.decode(Int64.self, forKey: .id)
let name = try values.decode(String.self, forKey: .name)
let image = try values.decode(String.self, forKey: .image)
let owned = try values.decode(Int.self, forKey: .owned)
let price = try values.decode(Double.self, forKey: .price)
let updatedAt = try values.decode(Date.self, forKey: .updatedAt)
let createdAt = try values.decode(Date.self, forKey: .createdAt)
self.id = id
self.name = name
self.image = URL(string: image)
self.owned = owned == 1
self.price = price
self.updatedAt = updatedAt
self.createdAt = createdAt
}
init(context: NSManagedObjectContext) {
guard let entity = NSEntityDescription.entity(forEntityName: "Tour", in: context) else { fatalError() }
super.init(entity: entity, insertInto: context)
}
}
数据解码器:
class DataDecoder: JSONDecoder {
// MARK: - Variables
var context: NSManagedObjectContext!
private var persistent: Bool = true
// MARK: - Initializers
public init(persistent: Bool = true, context: NSManagedObjectContext) {
super.init()
self.dateDecodingStrategy = .custom({ (decoder) -> Date in
let container = try decoder.singleValueContainer()
let string = try container.decode(String.self)
let dateFormatter = DateFormatter()
locale = .autoupdatingCurrent
dateFormat = "yyyy-MM-dd HH:mm:ss"
return dateFormatter.date(from: string)!
})
self.context = context
userInfo[.context] = context
}
// MARK: - Utilities
public func decode<T>(_ type: T.Type, from data: Data, completion: (() -> Void)? = nil) throws -> T where T : Decodable {
let result = try super.decode(type, from: data)
if(persistent) {
saveContext(completion: completion)
}
return result
}
private func saveContext(completion: (() -> Void)? = nil) {
guard let context = context else { fatalError("Cannot Find Decoding Context") }
context.performAndWait {
try? context.save()
completion?()
context.reset()
}
}
}
编码用户信息密钥扩展:
extension CodingUserInfoKey {
static let context = CodingUserInfoKey(rawValue: "context")!
}
completion
闭包对其Error
参数的期望与它从CoreDataModel.create
完成闭包的推断类型(Error?
(获得的类型不匹配:
public func syncTours(page: Int, completion: @escaping(Bool, Error, Bool) -> Void) {
...
CoreDataModel.create(Array<Tour>.self, from: data) { success, error in
// error is of type Error?, but completion expects Error
completion(success, error, false)
}
...
}
通常,每当您遇到类型推断问题或错误时,请明确每个类型,您将确切地看到不匹配的位置。例如,下面您可以明确说明内部闭包签名:
CoreDataModel.create([Tour].self, from: data) { (success: Bool, err: Error?) -> Void in
}