如何解决解码期间未从其他结构中找到 CodingKey
我正在尝试使用 dateString
结构中的解析日期字符串 (Datum
) 在 AzimuthAtDate
类中构建新的日期对象...
{
"11": [{
"name": "Sun","date": "2021-01-26","rising": [{
"coord": "113.6681","hour": "07:16"
}],"transit-sup": [{
"coord": "32.4711","hour": "12:16"
}],"setting": [{
"coord": "246.4743","hour": "17:17"
}]
}]
}
struct Datum: Codable,CustomStringConvertible {
let name: String
let dateString: String
let isoDate: Date?
let rising: [AzimuthAtDate]
let transit: [ElevationAtDate]
let setting: [AzimuthAtDate]
enum CodingKeys: String,CodingKey {
case name
case dateString = "date"
case isoDate
case rising = "rising"
case transit = "transit-sup"
case setting = "setting"
}
init(from decoder: Decoder) throws {
let con = try decoder.container(keyedBy: CodingKeys.self)
self.name = try con.decode(String.self,forKey: .name)
self.dateString = try con.decode(String.self,forKey: .dateString)
self.isoDate = try con.decode(Date.self,forKey: .dateString)
self.rising = decodeAzimuthAtDate(decoder: decoder,key: .rising)
self.transit = decodeElevationAtDate(decoder: decoder,key: .transit)
self.setting = decodeAzimuthAtDate(decoder: decoder,key: .setting)
}
}
class CoordHour: Codable {
let coord: String
let hour: String
var isoDate: Date?
init(coord: String,hour: String,isoDate: Date?) {
self.coord = coord
self.hour = hour
self.isoDate = isoDate
}
}
但是在尝试从 Datum.CodingKeys
中访问 AzimuthAtDate
的密钥时,datumContainer
没有密钥。所以我收到这样的错误:
keyNotFound(CodingKeys(stringValue: "date",intValue: nil) ... debugDescription: "No value associated with key CodingKeys(stringValue: \"date\",intValue: nil) (\"date\").",underlyingError: nil))
class AzimuthAtDate: CoordHour {
required init(from decoder: Decoder) throws {
let coordHourContainer = try decoder.container(keyedBy: CoordHour.CodingKeys.self)
let coord = try coordHourContainer.decode(String.self,forKey: .coord)
let hour = try coordHourContainer.decode(String.self,forKey: .hour)
print("coord:\(coord) - hour:\(hour)") // prints correct info
let datumContainer = try decoder.container(keyedBy: Datum.CodingKeys.self)
print("datumContainer keys:\(datumContainer.allKeys)") // shows []
let dateString = try datumContainer.decode(String.self,forKey: .dateString)
print("dateString:\(dateString)")
let currentTZ = TimeZone.currentOffsetFromUTCString
let isoDateString = "\(dateString)T\(hour)\(currentTZ)"
let isoDate = DateFormatter.Iso.date(from: isoDateString)
super.init(coord: coord,hour: hour,isoDate: isoDate)
}
}
在 AzimuthAtDate
类中,我如何才能访问 Datum.dateString
键以便我可以使用它的值来形成 isoDate
?
func decodeAzimuthAtDate(decoder: Decoder,key: Datum.CodingKeys) -> [AzimuthAtDate] {
var result = [AzimuthAtDate]()
do {
let con = try decoder.container(keyedBy: Datum.CodingKeys.self)
if let az = try con.decode([AzimuthAtDate]?.self,forKey: key)?.first {
result.append(az)
}
} catch let error {
print(error)
}
return result
}
解决方法
忽略解码和 JSON 并用更一般的术语思考问题。内部结构如何知道将其作为属性保存的外部结构?
例如,这里会发生什么:
struct InnerStruct {
func test() {
// ?
}
}
struct OuterStruct {
let inner = InnerStruct()
let other = "howdy"
}
... 为了调用 inner
的 test()
打印 "howdy"
?显然,inner
的 InnerStruct 需要一个 引用 到持有它的 OuterStruct。像这样:
struct InnerStruct {
weak var container : OuterStruct?
func test() {
print(self.container?.other)
}
}
class OuterStruct {
var inner = InnerStruct()
let other = "howdy"
init() {
self.inner.container = self
}
}
let outerStruct = OuterStruct()
outerStruct.inner.test()
这就是你需要做的事情。您的内部类型需要一个属性,该属性是对其容器的引用,以便它们可以“看到”该日期,并且您需要在配置其他所有内容时设置该引用。否则,您甚至可以仅使用外部日期来设置内部类型的属性。但是你不能把它作为解码的一部分;必须在一切配置完成后才能完成。
以下是一种基于您的数据的简单示例(这是 Playground 代码):
let json = """
{
"11": [{
"name": "Sun","date": "2021-01-26","rising": [{
"coord": "113.6681","hour": "07:16"
}],"transit-sup": [{
"coord": "32.4711","hour": "12:16"
}],"setting": [{
"coord": "246.4743","hour": "17:17"
}]
}]
}
"""
let jsonData = json.data(using: .utf8)
class Inner: Decodable,CustomStringConvertible {
let coord : String
let hour : String
var outerDate : String?
var description : String {
return (self.coord + ";" + self.hour + ";" + (self.outerDate ?? ""))
}
}
struct Outer: Decodable {
let name: String
let date: String
let rising: [Inner]
let transitsup: [Inner]
let setting: [Inner]
enum CodingKeys: String,CodingKey {
case name
case date
case rising
case transitsup = "transit-sup"
case setting
}
}
struct Main: Decodable {
let x: [Outer]
enum CodingKeys: String,CodingKey {
case x = "11"
}
}
let result = try! JSONDecoder().decode(Main.self,from: jsonData!)
let outers = result.x
for anOuter in outers {
let date = anOuter.date
for anInner in anOuter.rising {
anInner.outerDate = date
}
for anInner in anOuter.setting {
anInner.outerDate = date
}
for anInner in anOuter.transitsup {
anInner.outerDate = date
}
}
print(outers)
如您所见,当我们完成后,每个 Inner 都知道其容器的 date
。因此它可以继续计算日期时间。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。