解析JSON时出现可解码问题



我正在尝试分析工作日的JSON时间表数据,每个工作日都有一系列不同的事件/时间表,这些事件/时间表重复每个薄弱环节。所以我有一个数据数组,它有从星期一到星期天的工作日对象,而工作日有一个事件/时间表数组。

struct Scheduledata: Decodable {
let data: [WeekDay]
}
struct WeekDay: Decodable {
let monday, tuesday, wednesday, thursday, friday, saturday, sunday : [Schedule]?
}
struct Schedule: Decodable {
let id: Int?
let start: String?
let end: String?
let address: String?
let name: String?
let text: String?
let imageURL: String?
let location: CLLocationCoordinate2D?

enum CodingKeys: String, CodingKey {
case text, location, start, end, name, address, id
case imageURL = "image_url"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeIfPresent(Int.self, forKey: .id)
text = try container.decodeIfPresent(String.self, forKey: .text)
imageURL = try container.decodeIfPresent(String.self, forKey: .imageURL)
location = try container.decodeIfPresent(CLLocationCoordinate2D.self, forKey: .location)
start = try container.decodeIfPresent(String.self, forKey: .start)
end = try container.decodeIfPresent(String.self, forKey: .end)
address = try container.decodeIfPresent(String.self, forKey: .address)
name = try container.decodeIfPresent(String.self, forKey: .name)
}
}

extension CLLocationCoordinate2D: Codable {
public init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
self.init()
longitude = try container.decode(Double.self)
latitude = try container.decode(Double.self)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(longitude)
try container.encode(latitude)
}
}

这是我试图解析的json对象

{
"data": [
{
"monday": []
},
{
"tuesday": [
{
"id": 1,
"day_id": 2,
"start": "16:30",
"end": "21:00",
"name": "Test Event",
"address": "6 mohamed galal street cairo, heliopolis",
"lat": "30.0866280",
"long": "31.3236130",
"image": "http://80.211.174.200/img/event/1542547661.jpeg",
"title": "Test_Event",
"description": "This is just a test event to test the testable testi test test testit test............................. yes this is a test indeed",
"created_at": "2018-11-18 15:27:41",
"updated_at": "2018-11-18 15:27:41"
}
]
},
{
"wednesday": []
},
{
"thursday": []
},
{
"friday": []
},
{
"saturday": []
},
{
"sunday": []
}
]
}

我期待的是一本字典:

var schedule = ["monday":[schedule], "tuesday":[schedule], ...]

我得到的似乎是一大堆字典。我在每个工作日只有一天,而不是一周中的所有日子。

var schedule = [["monday":[schedule], "tuesday":[schedule], ...],["monday":[schedule], "tuesday":[schedule], ...]]

那么我该怎么做呢?我为每天创建不同的结构,而不是工作日结构?这似乎不符合逻辑。有些事情不太对劲。我相信有一个更聪明的解决方案来解析这个问题。

您的代码有两个问题:

1:您将许多属性声明为可选。当你这样做的时候,你就把错误藏起来了。你希望这在测试过程中成功或失败,这样你就知道在哪里调试,而不是用Optionals把它掩盖起来。

struct WeekDay: Decodable {
let monday, tuesday, ... : [Schedule]?
}
struct Schedule: Decodable {
let id: Int?
let start: String?
let end: String?
let address: String?
...
}

2:您的JSON真的很难使用。如果您可以控制服务器端,请将其更改为:

{
"data": [
"monday": [],
"tuesday": [{...}, {...}, ...],
"wednesday": [],
"thursday": [],
"friday": [],
"saturday": [],
"sunday": [],
]
}

假设您无法更改JSON,以下是如何解码坏的JSON:

import Foundation
import CoreLocation
struct WeeklySchedule: Decodable {
let monday, tuesday, wednesday, thursday, friday, saturday, sunday: [Schedule]
private enum CodingKeys: String, CodingKey {
case data
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
// Get the content of the `data` key from JSON
var subContainer = try container.nestedUnkeyedContainer(forKey: .data)
// Since you declare `monday`, etc. as `let` properties, they cannot
// be assigned multiple time. And the compiler does not know how
// many times the variable will be assigned to a `while` loop. So we
// need to define some local variables to temporarily hold the values.
var monday, tuesday, wednesday, thursday, friday, saturday, sunday: [Schedule]!
while !subContainer.isAtEnd {
let dailySchedule = try subContainer.decode([String: [Schedule]].self)
// The `first` value of a dictionary is non-deterministic since
// dictionaries do not have an order. But if the dictionary
// contains more than one weekday, there's a problem with the
// JSON anyway.
guard let (weekday, schedule) = dailySchedule.first else { continue }
switch weekday {
case "monday": monday = schedule
case "tuesday": tuesday = schedule
case "wednesday": wednesday = schedule
case "thursday": thursday = schedule
case "friday": friday = schedule
case "saturday": saturday = schedule
case "sunday": sunday = schedule
default: break
}
}
self.monday    = monday
self.tuesday   = tuesday
self.wednesday = wednesday
self.thursday  = thursday
self.friday    = friday
self.saturday  = saturday
self.sunday    = sunday
}
}
struct Schedule: Decodable {
let id: Int
let start: String
let end: String
let address: String
let name: String
let text: String
let imageURL: URL
let location: CLLocationCoordinate2D
private enum CodingKeys: String, CodingKey {
case start, end, name, address, id
case imageURL = "image", text = "description"
case lat, long
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id       = try container.decode(Int.self, forKey: .id)
self.start    = try container.decode(String.self, forKey: .start)
self.end      = try container.decode(String.self, forKey: .end)
self.address  = try container.decode(String.self, forKey: .address)
self.name     = try container.decode(String.self, forKey: .name)
self.text     = try container.decode(String.self, forKey: .text)
self.imageURL = try container.decode(URL.self, forKey: .imageURL)
let latStr  = try container.decode(String.self, forKey: .lat)
let longStr = try container.decode(String.self, forKey: .long)
guard let lat = CLLocationDegrees(latStr), let long = CLLocationDegrees(longStr) else {
fatalError("lat / long is not a number")
}
self.location = CLLocationCoordinate2D(latitude: lat, longitude: long)
}
}
let weeklySchedule = try JSONDecoder().decode(WeeklySchedule.self, from: jsonData)

相关内容

  • 没有找到相关文章

最新更新