Ios 如何使用Swift可解码属性解码具有嵌套数组的嵌套字典?

Ios 如何使用Swift可解码属性解码具有嵌套数组的嵌套字典?,ios,swift,decodable,Ios,Swift,Decodable,我需要在swift4中解析的实际JSON是 { "class": { "semester1": [ { "name": "Kal" }, { "name": "Jack" }, { "name": "Igor" } ],

我需要在swift4中解析的实际JSON是

{
    "class": {
        "semester1": [
            {
                "name": "Kal"
            },
            {
                "name": "Jack"
            },
            {
                "name": "Igor"
            }
        ],
        "subjects": [
            "English",
            "Maths"
        ]
    },
    "location": {
        "Dept": [
            "EnglishDept",
            ],
        "BlockNo": 1000
    },
    "statusTracker": {
        "googleFormsURL": "beacon.datazoom.io",
        "totalCount": 3000
    }
}
我尝试但未能执行的代码是

struct Class: Decodable {
    let semester: [internalComponents]
    let location: [location]
    let statusTracker: [statusTracker]
    enum CodingKeys: String, CodingKey {
        case semester = "semester1"
        case location = "location"
        case statusTracker = "statusTracker"
    }
}
struct location: Decodable {
    let Dept: [typesSubIn]
    let BlockNo: Int
}
struct statusTracker: Decodable {
    let googleFormsURL: URL
    let totalCount: Int
}


struct internalComponents: Decodable {
    let semester1: [semsIn]
    let subjects: [subjectsIn]
}
struct semsIn: Decodable {
    let nameIn: String
}
struct subjectsIn: Decodable {
    let subjects: String
}
struct Dept: Decodable {
    let Depts: String
}

我知道这是完全错误的有人能给出实际的格式吗?实际上,我对“主题”的格式感到困惑。它也不是作为一个整体编译的。

看起来你用错误的方式消毒了
Class
对象。应该是这样的:

struct Class: Decodable {
    let class: [internalComponents]
    let location: [location]
    let statusTracker: [statusTracker]
}

这里有一些事情导致了您的问题

  • 您没有顶级项目,我添加了响应结构
  • 位置、类和状态跟踪器都处于同一级别,而不是在类之下
  • 在类结构中,项被设置为数组,但它们不是数组
  • 要调试这些类型的问题,请将解码包装在do catch块中并打印出错误。它将告诉您无法解析的原因
在我的游乐场上尝试以下代码:

let jsonData = """
{
    "class": {
        "semester1": [{
            "name": "Kal"
        }, {
            "name": "Jack"
        }, {
            "name": "Igor"
        }],
        "subjects": [
            "English",
            "Maths"
        ]
    },
    "location": {
        "Dept": [
            "EnglishDept"
        ],
        "BlockNo": 1000
    },
    "statusTracker": {
        "googleFormsURL": "beacon.datazoom.io",
        "totalCount": 3000
    }
}
""".data(using: .utf8)!

struct Response: Decodable {
    let cls: Class
    let location: Location
    let statusTracker: statusTracker

    enum CodingKeys: String, CodingKey {
        case cls = "class"
        case location
        case statusTracker
    }
}

struct Class: Decodable {
    let semester: [SemesterStudents]
    let subjects: [String]

    enum CodingKeys: String, CodingKey {
        case semester = "semester1"
        case subjects
    }
}

struct Location: Decodable {
    let dept: [String]
    let blockNo: Int

    enum CodingKeys: String, CodingKey {
        case dept = "Dept"
        case blockNo = "BlockNo"
    }
}

struct statusTracker: Decodable {
    let googleFormsURL: URL
    let totalCount: Int
}

struct SemesterStudents: Decodable {
    let name: String
}

struct Dept: Decodable {
    let Depts: String
}

do {
    let result = try JSONDecoder().decode(Response.self, from: jsonData)
    print(result)
} catch let error {
    print(error)
}
有很多问题

忽略部分根对象是一个常见错误

请看一下JSON:在顶层有3个键
class
location
statusTracker
。所有3个键的值都是字典,没有数组

由于
class
(小写)是一个保留字,所以我使用
组件
。顺便说一下,请遵守命名约定,结构名称以大写字母开头

struct Root : Decodable {
    let components : Class
    let location: Location
    let statusTracker: StatusTracker

    enum CodingKeys: String, CodingKey { case components = "class", location, statusTracker }
}
还有许多其他问题。这里是其他结构的合并版本

struct Class: Decodable {
    let semester1: [SemsIn]
    let subjects : [String]
}

struct Location: Decodable {
    let dept : [String]
    let blockNo : Int

    enum CodingKeys: String, CodingKey { case dept = "Dept", blockNo = "BlockNo" }
}

struct SemsIn: Decodable {
    let name: String
}

struct StatusTracker: Decodable {
    let googleFormsURL: String // URL is no benefit
    let totalCount: Int
}
现在解码
Root

do {
    let result = try decoder.decode(Root.self, from: data)
} catch { print(error) }

另一种方法是创建一个与JSON紧密匹配的中间模型,让Swift生成解码方法,然后在最终数据模型中挑选您想要的片段:

// snake_case to match the JSON
fileprivate struct RawServerResponse: Decodable {
    struct User: Decodable {
        var user_name: String
        var real_info: UserRealInfo
    }

    struct UserRealInfo: Decodable {
        var full_name: String
    }

    struct Review: Decodable {
        var count: Int
    }

    var id: Int
    var user: User
    var reviews_count: [Review]
}

struct ServerResponse: Decodable {
    var id: String
    var username: String
    var fullName: String
    var reviewCount: Int

    init(from decoder: Decoder) throws {
        let rawResponse = try RawServerResponse(from: decoder)

        // Now you can pick items that are important to your data model,
        // conveniently decoded into a Swift structure
        id = String(rawResponse.id)
        username = rawResponse.user.user_name
        fullName = rawResponse.user.real_info.full_name
        reviewCount = rawResponse.reviews_count.first!.count
    }
}

Clean and preciseSwift 4.1将
keyDecodingStrategy
带到表中:
decoder.keyDecodingStrategy=.convertFromSnakeCase