Swift 动态 json 读写值
Swift Dynamic json Values Reading and Writing
问题卡在
我正在尝试能够将我的 json 文件数据读出到控制台日志以进行测试,以便我以后可以使用它。
由于不同的数据大小和可能的错误 json 格式,我不确定如何完成我的其他结构。
完成后,我相信我需要使用 for 循环从“M”、“S”和“WP”读取不同大小的数据(我认为这部分不应该很复杂)
可能需要考虑的事项
我要写入和添加数据到“M”“S”“WP”
("M", "S") 的数据量可以是任意数量的字符串数组数据对象
“WP”中的数据可能需要不同的格式我想添加一个名称(“abc”)和一个包含任意数量数据点的 Int 数组
注意:我的Json格式在MP和WP的某些地方可能是错误的
Swift 抓取数据的代码
import Foundation
struct UserDay: Codable {
let mp: UserMP
let wp: UserWP
}
struct UserMP: Codable {
let m: [UserM]
let s: [UserS]
}
struct UserM : Codable {
let title: String
let description: String
let time: String
}
struct UserS : Codable {
let title: String
let description: String
let time: String
}
struct UserWP: Codable {
let wp: [WPData]
}
struct WPData: Codable {
let title: String
let values: [Int]
}
class LogDataHandler {
public func grabJSONInfo(){
guard let jsonURL = Bundle(for: type(of: self)).path(forResource: "LogData", ofType: "json") else { return }
guard let jsonString = try? String(contentsOf: URL(fileURLWithPath: jsonURL), encoding: String.Encoding.utf8) else { return }
// Print Info for TESTING
var year: UserDay?
do {
year = try JSONDecoder().decode(UserDay.self, from: Data(jsonString.utf8))
} catch {
print("ERROR WHEN DECODING JSON")
}
guard let results = year else {
print("YEAR IS NIL")
return
}
print(results)
}
}
JSON 下面的示例数据
{
"01/01/2020": {
"MP" : {
"M" : [
{"title" : "m1", "description" : "1", "time" : "12:30pm"},
{"title" : "m2", "description" : "2", "time" : "1:30pm"},
{"title" : "m3", "description" : "3", "time" : "2:30pm"}
],
"S" : [
{"title" : "s1", "description" : "1", "time" : "1pm"}
]
},
"WP" : [
{ "title" : "abc", "values" : [12, 10, 6]},
{ "title" : "def", "values" : [8]}
]
},
"01/29/2020": {
"MP" : {
"M" : [{"title" : "m1", "description" : "1", "time" : "12:30pm"}],
"S" : [{"title" : "s1", "description" : "1", "time" : "12:30pm"}]
},
"WP" :[{ "title" : "def", "values" : [8]}]
}
}
根据评论和我们的聊天,这似乎是构建 Swift 模型和 JSON 对象的正确方法的问题。
根据您的(更新的)JSON,您可能希望将数据解码为 [String: UserDay]
- 一个以日期字符串为键、以 UserDay
为值的字典。
First, WP
属性 在你的 JSON 中只是一个对象数组(映射到 WPData
) , 所以最好将 UserDay.wp
改为 [WPData]
而不是 UserWP
:
struct UserDay: Codable {
let mp: UserMP
let wp: [WPData] // <-- changed
}
其次,您的某些模型属性与 JSON 中的内容不直接匹配,因为键-属性映射区分大小写。您可以显式定义 CodingKeys
来映射它们:
struct UserDay: Codable {
let mp: UserMP
let wp: [WPData]
enum CodingKeys: String, CodingKey {
case mp = "MP", wp = "WP"
}
}
struct UserMP: Codable {
let m: [UserM]
let s: [UserS]
enum CodingKeys: String, CodingKey {
case m = "M", s = "S"
}
}
现在您已准备好解码 [String: UserDay]
:
let userDays = try JSONDecoder().decoder([String: UserDay].self, from: jsonData)
let userDay = userDays["01/29/2020"]
当然,使用 String
而不是 Date
不是很方便。不幸的是,Dictionary
与 Codable
的一致性仅支持 Int
或 String
作为键(AFAIK)。
所以,让我们手动解码成一个新的根对象 UserData
,它适用于 Date
s:
struct UserData: Codable {
var userDays: [Date: UserDay]
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let dict = try container.decode([String: UserDay].self)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
// decode (String, UserDay) pairs into an array of (Date, UserDay)
let pairs = dict.compactMap { (key, value) -> (Date, UserDay)? in
guard let date = dateFormatter.date(from: key) else { return nil }
return (date, value)
}
// uniquing is used just in case there non unique keys
self.userDays = Dictionary(pairs, uniquingKeysWith: {(first, _) in first})
}
}
现在,我们可以解码成这个 UserData
对象:
let userData = try JSONDecoder().decode(UserData.self, from: jsonData)
let todaysData = userData.userDays[Date()]
问题卡在
我正在尝试能够将我的 json 文件数据读出到控制台日志以进行测试,以便我以后可以使用它。
由于不同的数据大小和可能的错误 json 格式,我不确定如何完成我的其他结构。
完成后,我相信我需要使用 for 循环从“M”、“S”和“WP”读取不同大小的数据(我认为这部分不应该很复杂)
可能需要考虑的事项
我要写入和添加数据到“M”“S”“WP”
("M", "S") 的数据量可以是任意数量的字符串数组数据对象
“WP”中的数据可能需要不同的格式我想添加一个名称(“abc”)和一个包含任意数量数据点的 Int 数组
注意:我的Json格式在MP和WP的某些地方可能是错误的
Swift 抓取数据的代码
import Foundation
struct UserDay: Codable {
let mp: UserMP
let wp: UserWP
}
struct UserMP: Codable {
let m: [UserM]
let s: [UserS]
}
struct UserM : Codable {
let title: String
let description: String
let time: String
}
struct UserS : Codable {
let title: String
let description: String
let time: String
}
struct UserWP: Codable {
let wp: [WPData]
}
struct WPData: Codable {
let title: String
let values: [Int]
}
class LogDataHandler {
public func grabJSONInfo(){
guard let jsonURL = Bundle(for: type(of: self)).path(forResource: "LogData", ofType: "json") else { return }
guard let jsonString = try? String(contentsOf: URL(fileURLWithPath: jsonURL), encoding: String.Encoding.utf8) else { return }
// Print Info for TESTING
var year: UserDay?
do {
year = try JSONDecoder().decode(UserDay.self, from: Data(jsonString.utf8))
} catch {
print("ERROR WHEN DECODING JSON")
}
guard let results = year else {
print("YEAR IS NIL")
return
}
print(results)
}
}
JSON 下面的示例数据
{
"01/01/2020": {
"MP" : {
"M" : [
{"title" : "m1", "description" : "1", "time" : "12:30pm"},
{"title" : "m2", "description" : "2", "time" : "1:30pm"},
{"title" : "m3", "description" : "3", "time" : "2:30pm"}
],
"S" : [
{"title" : "s1", "description" : "1", "time" : "1pm"}
]
},
"WP" : [
{ "title" : "abc", "values" : [12, 10, 6]},
{ "title" : "def", "values" : [8]}
]
},
"01/29/2020": {
"MP" : {
"M" : [{"title" : "m1", "description" : "1", "time" : "12:30pm"}],
"S" : [{"title" : "s1", "description" : "1", "time" : "12:30pm"}]
},
"WP" :[{ "title" : "def", "values" : [8]}]
}
}
根据评论和我们的聊天,这似乎是构建 Swift 模型和 JSON 对象的正确方法的问题。
根据您的(更新的)JSON,您可能希望将数据解码为 [String: UserDay]
- 一个以日期字符串为键、以 UserDay
为值的字典。
First, WP
属性 在你的 JSON 中只是一个对象数组(映射到 WPData
) , 所以最好将 UserDay.wp
改为 [WPData]
而不是 UserWP
:
struct UserDay: Codable {
let mp: UserMP
let wp: [WPData] // <-- changed
}
其次,您的某些模型属性与 JSON 中的内容不直接匹配,因为键-属性映射区分大小写。您可以显式定义 CodingKeys
来映射它们:
struct UserDay: Codable {
let mp: UserMP
let wp: [WPData]
enum CodingKeys: String, CodingKey {
case mp = "MP", wp = "WP"
}
}
struct UserMP: Codable {
let m: [UserM]
let s: [UserS]
enum CodingKeys: String, CodingKey {
case m = "M", s = "S"
}
}
现在您已准备好解码 [String: UserDay]
:
let userDays = try JSONDecoder().decoder([String: UserDay].self, from: jsonData)
let userDay = userDays["01/29/2020"]
当然,使用 String
而不是 Date
不是很方便。不幸的是,Dictionary
与 Codable
的一致性仅支持 Int
或 String
作为键(AFAIK)。
所以,让我们手动解码成一个新的根对象 UserData
,它适用于 Date
s:
struct UserData: Codable {
var userDays: [Date: UserDay]
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let dict = try container.decode([String: UserDay].self)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
// decode (String, UserDay) pairs into an array of (Date, UserDay)
let pairs = dict.compactMap { (key, value) -> (Date, UserDay)? in
guard let date = dateFormatter.date(from: key) else { return nil }
return (date, value)
}
// uniquing is used just in case there non unique keys
self.userDays = Dictionary(pairs, uniquingKeysWith: {(first, _) in first})
}
}
现在,我们可以解码成这个 UserData
对象:
let userData = try JSONDecoder().decode(UserData.self, from: jsonData)
let todaysData = userData.userDays[Date()]