如何使用与 NewtonSoft (JSON.Net) 组件中的 JSON 匹配的 Swift 类从/向 JSON 读取/写入对象数组?

Posted

技术标签:

【中文标题】如何使用与 NewtonSoft (JSON.Net) 组件中的 JSON 匹配的 Swift 类从/向 JSON 读取/写入对象数组?【英文标题】:How can I Read/Write array of objects from/to JSON using a Swift class that matches JSON from NewtonSoft (JSON.Net) component? 【发布时间】: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;
     

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

【问题讨论】:

【参考方案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 类对象数组。

【讨论】:

以上是关于如何使用与 NewtonSoft (JSON.Net) 组件中的 JSON 匹配的 Swift 类从/向 JSON 读取/写入对象数组?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 C# 进行条件序列化 - NewtonSoft.Json

如何使用 Newtonsoft 反序列化 EPOCH

您如何“真正”使用 Newtonsoft.Json 序列化循环引用对象?

如何使用 Newtonsoft.JSON 解析 JSON 响应? [复制]

如何在MS构建任务中使用NewtonSoft.json?

在Asp.Net Core 3.0中如何使用 Newtonsoft.Json 库序列化数据