swift - 使用带有注入属性的 Decodable
问题描述
有没有办法使用Decodable
注入的属性?
final class Score: Decodable {
let value: Int?
let uniqueId: String
convenience init(from decoder: Decoder/*, uniqueId: String*/) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
try container.decodeIfPresent(Int.self, forKey: .value).flatMap { value = $0 }
// self.uniqueId = uniqueId
[... other properties parsing ...]
}
}
示例调用:
final class Exam {
let identifier: Int
let scores: [Score]
convenience init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
identifier = try container.decode(Int.self, forKey: .identifier)
scores = try container.decode([Score].self, forKey: .scores)
// I need to pass Exam's identifier to `score` on init, because it will generate Score's `uniqueId `
[... other properties parsing ...]
}
}
这将以 missing 错误结束uniqueId
,我需要在 init 之后拥有它,但它不在 JSON 中。由于它是标识符,因此将其设为可选并设置在外部并不是处理它的正确方法。
我很想按照上面评论的方式注入它,但是怎么做呢?
解决方案
无法扩展初始化程序,因为它是间接调用的,并且没有提供 API 来扩展它。因此,有几种方法可以绕过它:
userInfo
最佳:如果可能,将值注入解码器。- 为响应创建单独的类,为模型创建单独的类。下面的例子。
- 使用普通
JSONSerialization
的而不是Decodable
. - 正如@JoakimDanielson 建议的那样,在默认初始化程序中创建随机标识符。问题是它不可重现,因此如果您将其保存到数据库中,您将始终覆盖数据,因为每次解析的 ID 都会不同。
方法 2 的示例:
final class ScoreResponse: Decodable {
let value: Int?
convenience init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
try container.decodeIfPresent(Int.self, forKey: .value).flatMap { value = $0 }
[... other properties parsing ...]
}
}
final class Score {
let value: Int?
let uniqueId: String
convenience init(from response: ScoreResponse, uniqueId: String) {
self.value = response.value // etc with other properties
self.uniqueId = uniqueId
}
}
final class Exam: Decodable {
let identifier: String
let scores: [Score] = []
convenience init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
identifier = try container.decode(String.self, forKey: .identifier)
try container.decodeIfPresent([ScoreResponse].self, forKey: .scores).forEach {
scores.append({ Score(from: $0, uniqueId: identifier) })
}
}
推荐阅读
- javascript - Protractor 的 getText() 方法不包括在 ::first-letter 伪选择器中完成的文本转换
- java - 使用 in.hasNextInt() 时,如何跳过同一行中的字符串?
- python - Microbit Python Neopixel RGBW
- r - 绘制三个值 x 轴
- apache-kafka - Kafka Streams 2.1.1 类转换同时刷新定时聚合以存储
- node.js - Mongoose 独特的属性仍然允许我保存到数据库
- csound - CSound 中任意长度的两个表的包络
- android - 在应用关闭的情况下调用 Xamarin.Forms 依赖服务
- javascript - getUserMedia 使用exact:deviceId为错误的相机创建流
- ajax - Async XMLHttpRequest 在后面跟着代码重定向到 Firefox 和 Safari 中的另一个 URL 时不返回响应