【问题标题】:Swift Dynamic json Values Reading and WritingSwift 动态 json 值读写
【发布时间】:2020-10-18 05:33:30
【问题描述】:

问题一直存在

我正在尝试能够将我的 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]}]
    }
    
}

【问题讨论】:

  • 您可以将有时缺少的属性设为可选。例如,在UserWP 中,您将拥有:var abc, def: [Int]?。但是,MS 不是带有 { [...],[...] } 的有效 JSON,因此如果您想使用 JSONDecoder 对其进行解码,则需要修复它
  • @NewDev 我更新了我的 json 和代码,但我的输出是 ERROR WHEN WHEN DECODING JSON and YEAR IS NIL
  • 当我打印本地化错误The data couldn’t be read because it isn’t in the correct format.时也会出现这个错误
  • 您的 JSON 格式仍然不正确 - 使用任何在线 JSON 验证器站点来修复它(例如:this)。您将面临的另一个挑战是monthX 属性。这将需要手动解码。还有,"1"s 是什么意思?这总是"1"吗?
  • @NewDev thats 1 只是一个天数,它只是显示第 1 天而不是第 1-30 天

标签: json swift struct encoding decoding


【解决方案1】:

根据 cmets 和我们的聊天,这似乎是构造 Swift 模型和 JSON 对象的正确方法的问题。

根据您的(更新的)JSON,您可能希望将数据解码为 [String: UserDay] - 一个以日期字符串为键、UserDay 为值的字典。

首先,您的 JSON 中的 WP 属性只是一个对象数组(映射到 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 不是很方便。不幸的是,DictionaryCodable 的一致性仅支持 IntString 作为键 (AFAIK)。

所以,让我们手动解码成一个新的根对象UserDataDates 一起使用:

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()]

【讨论】:

  • 如何使用 userDays userDay userData todaysData?或者你在哪里使用它们,当我尝试时出现此错误“无法将'String'类型的值转换为预期的参数类型'Data'”
  • 我用jsonString替换了解码中的jsonData,所以它来自json字符串
  • 哦.. 不,它需要类似于if let jsonData = jsonString.data(using: .utf8) { /* decode here */ }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-18
  • 2020-11-06
  • 1970-01-01
  • 1970-01-01
  • 2020-04-17
  • 1970-01-01
  • 2011-08-03
相关资源
最近更新 更多