【发布时间】:2018-11-17 10:30:41
【问题描述】:
我将核心数据对象包装到结构中以使它们可编码。
[注意:在您指导我为每个 Core Data 类编写 swift 文件之前,我想说包装 NSManagedObject 子代是有意识地选择有利于代码可维护性的结果,因为数据模型可能会在未来。]
我有几个这样的类,这里是一个例子:
struct CodableNeed : Codable {
enum CodingKeys: String, CodingKey {
...
}
var need:Need
init (_ need:Need) {
self.need = need
}
init(from decoder: Decoder) throws {
....
}
func encode(to encoder: Encoder) throws {
....
}
}
这实际上工作得很好,因为结构的 init(from:decoder) 中的任何更新实际上都存储在 ManagedObjectContext 中。
为了让每个 NSManagedObject 类实例返回它们自己的结构体,我定义了一个协议,每个类实例都可以返回它们自己的 Codable 结构体:
protocol CodableWhenWrapped {
func wrapToCodable() -> Codable
}
extension Need : CodableWhenWrapped {
func wrapToCodable() -> Codable {
return CodableNeed(self)
}
}
然后我在编码函数中使用它:
func jsonDataOfCodable<T:Encodable>(_ object:T) throws -> Data {
let encoder = JSONEncoder()
let data = try encoder.encode(object)
return data
}
我调用这个函数来生成一个URLSessionUploadTask:
func updateTaskFor<T: NSManagedObject> (_ object:T, withSession session:URLSession) throws -> URLSessionUploadTask
where T: CodableWhenWrapped
{
let encoder = JSONEncoder()
// Here is the compile error:
// " Cannot invoke 'jsonDataOfCodable' with an argument list of type '(Codable)' "
let jsonData = try jsonDataOfCodable(object.wrapToCodable())
// then continue with generating the uploadTask
let url = "https://myurl.com/"
let request = URLRequest(url: url)
let updateTask = session.uploadTask(with: request, from: jsonData) { (data, response, error) in
....
}
}
问题是:调用jsonDataOfCodable 时代码无法编译:Cannot invoke 'jsonDataOfCodable' with an argument list of type '(Codable)'。
知道为什么编译器不喜欢这样吗?
请注意,当我在 jsonDataOfCodable 原型中指定 <T:Codable> 而不是 <T:Encodable> 时,我遇到了同样的问题。
【问题讨论】:
-
JSONEncoder().encode需要符合(En)codable的具体类型,而不是协议Codable本身。您可以使用associatedtype。在每个NSManagedObject子类中实现init(from decoder:和encode(to encoder:可能更容易。特别是如果有关系,这是唯一的选择。
标签: swift core-data wrapper swift-protocols codable