Swift 5 (Xcode 11 Betas 5 & 6) - 如何写入 JSON 文件?

Jac*_*ord 6 filesystems xcode ios swift xcode11

多年来,这个问题已经被问过很多次了,但它在 Swift 5 中再次发生变化,尤其是在最近的两个测试版中。

读取 JSON 文件似乎很简单:

func readJSONFileData(_ fileName: String) -> Array<Dictionary<String, Any>> {

    var resultArr: Array<Dictionary<String, Any>> = []

    if let url = Bundle.main.url(forResource: "file", withExtension: "json") {

        if let data = try? Data(contentsOf: url) {

            print("Data raw: ", data)

            if let json = try? (JSONSerialization.jsonObject(with: data, options: []) as! NSArray) {

                print("JSON: ", json)

                if let arr = json as? Array<Any> {

                    print("Array: ", arr)

                    resultArr = arr.map { $0 as! Dictionary<String, Any> }

                }

            }

        }

    }

    return resultArr

}
Run Code Online (Sandbox Code Playgroud)

但是编写非常困难,并且在此站点上找到的所有以前的方法在 Xcode 11 betas 5 和 6 上的 Swift 5 中都失败了。

如何在 Swift 5 中将数据写入 JSON 文件?

我尝试了这些方法:

除了弃用警告之外没有任何错误,当我修复这些错误时,它根本不起作用。

Rob*_*Rob 13

让我们假设您有一些随机集合(数组或字典或它们的一些嵌套组合):

let dictionary: [String: Any] = ["bar": "qux", "baz": 42]
Run Code Online (Sandbox Code Playgroud)

然后你可以将它保存为 JSON 在“Application Support”目录中,如下所示:

do {
    let fileURL = try FileManager.default
        .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
        .appendingPathComponent("example.json")

    try JSONSerialization.data(withJSONObject: dictionary)
        .write(to: fileURL)
} catch {
    print(error)
}
Run Code Online (Sandbox Code Playgroud)

有关我们现在使用“Application Support”目录而不是“Documents”文件夹的原因,请参阅iOS 存储最佳实践视频或参考文件系统编程指南。但是,无论如何,我们使用这些文件夹,而不是应用程序的“捆绑”文件夹,后者是只读的。

并读取该 JSON 文件:

do {
    let fileURL = try FileManager.default
        .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        .appendingPathComponent("example.json")

    let data = try Data(contentsOf: fileURL)
    let dictionary = try JSONSerialization.jsonObject(with: data)
    print(dictionary)
} catch {
    print(error)
}
Run Code Online (Sandbox Code Playgroud)

话虽如此,我们通常更喜欢使用强类型的自定义类型,而不是随机字典,因为程序员的责任在于确保键名中没有拼写错误。无论如何,我们使这些自定义structclass类型符合Codable

struct Foo: Codable {
    let bar: String
    let baz: Int
}
Run Code Online (Sandbox Code Playgroud)

然后我们会使用JSONEncoder而不是旧的JSONSerialization

let foo = Foo(bar: "qux", baz: 42)
do {
    let fileURL = try FileManager.default
        .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
        .appendingPathComponent("example.json")

    try JSONEncoder().encode(foo)
        .write(to: fileURL)
} catch {
    print(error)
}
Run Code Online (Sandbox Code Playgroud)

并读取该 JSON 文件:

do {
    let fileURL = try FileManager.default
        .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        .appendingPathComponent("example.json")

    let data = try Data(contentsOf: fileURL)
    let foo = try JSONDecoder().decode(Foo.self, from: data)
    print(foo)
} catch {
    print(error)
}
Run Code Online (Sandbox Code Playgroud)

有关从自定义类型准备 JSON 的更多信息,请参阅编码和解码自定义类型文章或将JSON 与自定义类型一起使用示例代码。