【问题标题】:How can I Read/Write array of objects from/to JSON using a Swift class that matches JSON from NewtonSoft (JSON.Net) component?如何使用与 NewtonSoft (JSON.Net) 组件中的 JSON 匹配的 Swift 类从/向 JSON 读取/写入对象数组?
【发布时间】:2019-01-27 21:35:28
【问题描述】:

我正在尝试读取我在另一个 (Windows) 程序中使用 NewtonSoft JSON.Net 解析器创建的 JSON 文件。 JSON 是由 JSON.Net 组件在序列化对象数组时创建的。示例 JSON 如下所示(在此示例中,我只显示了两个对象):

[{"MaxLength":23,"HasSpecialChars":false,"HasUpperCase":true,"Key":"firstOne"},
{"MaxLength":0,"HasSpecialChars":false,"HasUpperCase":false,"Key":"secondOne"}]

请注意,这是 json 中的对象数组。

现在我需要一些 Swift 代码来读取这个 JSON,并在程序中更改值后将其写出。

我的尝试

我发现了这个 SO 条目:Reading in a JSON File Using Swift 但是,要获取对象数组,该条目使用可编码的单独结构,如下所示:

struct ResponseData: Decodable {
    var thisNameShowsUpInJson: [SiteKey]
}

这会强制外部数组在 json 中有自己的 name 属性。

例如,该帖子中的代码起作用的唯一方法是,如果我的 JSON 被更改为包含具有如下名称 (SiteKey) 的外部对象:

 {"thisNameShowsUpInJson": [{"MaxLength":23,"HasSpecialChars":false,"HasUpperCase":true,"Key":"firstOne"},
   {"MaxLength":0,"HasSpecialChars":false,"HasUpperCase":false,"Key":"secondOne"}]
}

但是,这对于 JSON.Net 将对象数组写入文件的方式是不正确的。

这是我想要序列化和反序列化的简单 Swift 类:

class SiteKey : Codable{
    var Key : String
    var MaxLength : Int
    var HasSpecialChars : Bool
    var HasUpperCase : Bool

    init(key : String, maxLength : Int,
         hasSpecialChars : Bool,
         hasUpperCase : Bool){
        Key = key;
        MaxLength = maxLength;
        HasSpecialChars = hasSpecialChars;
        HasUpperCase = hasUpperCase;
    } 
}

我想从命名文件中读取数据并将数据反序列化为对象。 然后,我想将内存中的对象序列化回一个文件,就像我的示例一样。

【问题讨论】:

    标签: ios arrays json swift


    【解决方案1】:

    假设您有一个可编码对象数组

    var array = [SiteKey]()
    

    然后您可以使用JSONEncoder 将整个数组简单地编码为Data

    do {
        let encoded = try JSONEncoder().encode(array)
    } catch { print(error) }
    

    要将Data 解码为对象数组,您可以使用JSONDecoder

    do {
        array = try JSONDecoder().decode([SiteKey].self, from: encoded)
    } catch { print(error) }
    

    我的建议:

    • 改为创建您的类结构,然后您可以删除硬编码的init,因为您可以免费获得一个
    • 用小写字母命名变量,然后在编码/解码时使用编码键重命名它

    struct SiteKey : Codable {
    
        var key : String
        var maxLength : Int
        var hasSpecialChars : Bool
        var hasUpperCase : Bool
    
        enum CodingKeys: String, CodingKey {
            case key = "Key"
            case maxLength = "MaxLength"
            case hasSpecialChars = "HasSpecialChars"
            case hasUpperCase = "HasUpperCase"
        }
    
    }
    

    【讨论】:

    • 这是非常好的附加信息。感谢发帖。
    【解决方案2】:

    我发现了我需要在 Swift 中使用的代码,它允许我读取和写入 JSON.Net 输出的 JSON(对象数组)。

    我在我的 SiteKey 对象中添加了两个方法:

    func loadJson(filename fileName: String) -> [SiteKey]
    func writeJson(filename fileName: String, allSiteKeys : [SiteKey])
    

    第一个函数接受一个指向 json 文件的字符串并返回文件中的 SiteKeys 数组。 第二个函数采用文件名和 SiteKey 对象数组并将它们写入文件。

    这里是修改后的 SiteKey 类,添加了一些功能。

    class SiteKey : Codable{
        var Key : String
        var MaxLength : Int
        var HasSpecialChars : Bool
        var HasUpperCase : Bool
    
        init(key : String, maxLength : Int,
             hasSpecialChars : Bool,
             hasUpperCase : Bool){
            Key = key;
            MaxLength = maxLength;
            HasSpecialChars = hasSpecialChars;
            HasUpperCase = hasUpperCase;
        }
    
        func loadJson(filename fileName: String) -> [SiteKey]? {
            if let url = Bundle.main.url(forAuxiliaryExecutable: fileName) {
                do {
                    let data = try Data(contentsOf: url)
                    let decoder = JSONDecoder()
                    let allKeys = try decoder.decode([SiteKey].self, from: data)
                    return allKeys
                } catch {
                    print("error:\(error)")
                }
            }
            return nil
        }
    
        func writeJson(filename fileName: String, allSiteKeys : [SiteKey]){
            let Data = try? JSONEncoder().encode(allSiteKeys)
    
                let pathAsURL = URL(fileURLWithPath: fileName)
                do {
                    try Data?.write(to: pathAsURL)
                }
                catch {
                    print("Failed to write JSON data: \(error.localizedDescription)")
                }
        }
    }
    

    用法如下:

    let newSiteKey = siteKey.loadJson(filename: "/Users/fakeUser/Documents/Dev/all.json")
    

    当 loadJson 方法返回时,newSiteKey 将包含一个可以迭代的 SiteKey 类对象数组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-24
      • 1970-01-01
      • 1970-01-01
      • 2019-05-23
      • 2021-10-06
      • 1970-01-01
      相关资源
      最近更新 更多