首页 > 解决方案 > 使用 Swift 在 JSON 中可解码的嵌套项

问题描述

我正在尝试解码从 reddit api 获得的一些 JSON。我想从数据中创建一个对象数组。问题是我想获取数据,但它嵌套了两层。

这是模型

struct Moderator: Codable {
    var name: String
}

这是我的网络管理器中尝试获取正确数据的部分。它不断击中 catch 块:

    do {
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        let moderators = try decoder.decode([Moderator].self, from: data)
        completed(moderators, nil)
    } catch {
        completed(nil, "Invalid data")
    }

我从这里得到 json:

https://www.reddit.com/r/videos/about/moderators.json

它的一个样本:

kind    "UserList"
data    
   children 
      0 
         name   "name3465"
         author_flair_text  null
         date   1297779059
         rel_id "rb_c32nl"
         id "t2_4d9s0"
         author_flair_css_class null
      1 
         name   "name2279"
         author_flair_text  null
         date   1300169101
         rel_id "rb_d151z"
         id "t2_1f8e1"
         author_flair_css_class null

标签: iosjsonswift

解决方案


作为示例ModeratorResponseModerator它是您希望在应用程序中使用的结构,并且RawModerator是一个私有结构,它隐藏了忽略您感兴趣的数据之间的嵌套结构的解析。看看这个例子,你可以在online.swiftplayground.run上尝试:

import Foundation

private struct RawModerator: Decodable {
    struct Data: Decodable {
        var children: [Moderator]
    }

    var kind: String
    var data: Data
}

struct ModeratorResponse: Decodable {
    var moderatorList: [Moderator]

    init(from decoder: Decoder) throws {
        let rawResponse = try RawModerator(from: decoder)
        moderatorList = rawResponse.data.children
    }
}

struct Moderator: Decodable {
    var name: String?
    var authorFlairTxt: String?
    var permissions: [String]?
    var date: Double?
    var rel_id: String
    var id: String
    var authorFlairCssClass: String?

    enum CodingKeys: String, CodingKey {
        case name = "name"
        case authorFlairTxt = "author_flair_text"
        case permissions = "mod_permissions"
        case date = "date"
        case rel_id = "rel_id"
        case id = "id"
        case authorFlairCssClass = "author_flair_css_class"
    }
}

let json = """
{
    "kind": "UserList", 
    "data": {
        "children": [
            {
                "name": "doug3465", 
                "author_flair_text": null, 
                "mod_permissions": ["all"], 
                "date": 1297779059.0, 
                "rel_id": "rb_c32nl", 
                "id": "t2_4d9s0", 
                "author_flair_css_class": null
            }, 

            {
                "name": "joka86", 
                "author_flair_text": null, 
                "mod_permissions": ["all"], 
                "date": 1571872041.0, 
                "rel_id": "rb_1k9iezh", 
                "id": "t2_36u6d", 
                "author_flair_css_class": null
            }
        ]
    }
}
""".data(using: .utf8)!

if let results = try? JSONDecoder().decode(ModeratorResponse.self, from: json) {
    for moderator in results.moderatorList {
        print("ID: \(moderator.id)")
        print("Name: \(moderator.name)")
    }
}

哪个输出:

ID: t2_4d9s0
Name: Optional("doug3465")
ID: t2_36u6d
Name: Optional("joka86")

推荐阅读