简体   繁体   English

如何使用与来自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?

I'm trying to read a JSON file that I've created using the NewtonSoft JSON.Net parser in another (Windows) program. 我正在尝试读取在另一个(Windows)程序中使用NewtonSoft JSON.Net解析器创建的JSON文件。 The JSON was created by the JSON.Net component when it serialized an array of objects. JSON是由JSON.Net组件在序列化对象数组时创建的。 The sample JSON looks like the following (for this example I'm just showing two of the objects): 样本JSON如下所示(在此示例中,我仅显示两个对象):

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

Notice that this is an array of objects in json. 请注意,这是json中的对象数组。

Now I need some Swift code that will read this JSON in and write it out after values are altered in the program. 现在,我需要一些Swift代码,该代码将读入JSON并在程序中更改值后将其写出。

What I've Tried 我尝试过的

I found this SO entry : Reading in a JSON File Using Swift However, to get an array of objects, that entry uses separate structs that are Codable like the following: 我找到了这个SO条目: 使用Swift读取JSON文件但是,为了获得对象数组,该条目使用了可编码的单独结构,如下所示:

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

That forces the outer array to have it's own name property in the json. 这迫使外部数组在json中拥有自己的name属性。

For example, the only way the code at that post works is if my JSON is altered to include an outer object with a name (SiteKey) like the following: 例如,该文章中代码的唯一工作方式是将我的JSON更改为包含名称(SiteKey)的外部对象,如下所示:

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

However, that is not correct for the way that JSON.Net writes an array of objects to a file. 但是,对于JSON.Net将对象数组写入文件的方式,这是不正确的。

Here's my simple Swift class that I want to serialize and deserialize: 这是我想要序列化和反序列化的简单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;
    } 
}

I'd like to read the data from a named file and deserialize the data into objects. 我想从命名文件中读取数据,然后将数据反序列化为对象。 Then, I'd like to serialize the in memory objects back out to a file like my example. 然后,我想将内存对象序列化回我的示例文件。

Imagine that you have an array of codable objects 想象一下,您有一组可编码的对象

var array = [SiteKey]()

then you can simply encode the entire array to Data using JSONEncoder 那么您只需使用JSONEncoder将整个数组编码为Data

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

To decode Data to your array of objects you can use JSONDecoder 要将Data解码为对象数组,可以使用JSONDecoder

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

My suggestions: 我的建议:

  • make your class struct instead, then you can remove hard-coded init since you get one for free 改用您的类结构,则可以删除硬编码的init因为您可以免费获得一个
  • name variables with small capital letter and then use coding keys for renaming it while encoding/decoding 用小写字母命名变量,然后在编码/解码时使用编码键对其重命名

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"
    }

}

I discovered the code I need to use in Swift which allows me to read and write the JSON (array of objects) that is output by JSON.Net. 我发现了需要在Swift中使用的代码,该代码使我可以读写JSON.Net输出的JSON(对象数组)。

I've added two methods to my SiteKey object : 我向SiteKey对象添加了两个方法:

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

The first function takes a string that points to a json file and returns the array of SiteKeys that is in the file. 第一个函数采用指向json文件的字符串,并返回文件中的SiteKeys数组。 The second function takes a filename and the array of SiteKey objects and writes them to the file. 第二个函数采用文件名和SiteKey对象数组,并将它们写入文件。

Here's the altered SiteKey class with the added functions. 这是带有附加功能的更改后的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)")
            }
    }
}

Here's the usage: 用法如下:

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

When the loadJson method returns the newSiteKey will contain an array of SiteKey class objects that can be iterated through. 当loadJson方法返回时,newSiteKey将包含可以迭代的SiteKey类对象的数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM