我需要在 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
}
我知道有人可以提供实际格式是完全错误的吗?我实际上对"主题"的格式感到困惑。它也不是作为一个整体进行编译。
有很多问题。
您犯了一个常见的错误,即部分忽略了根对象。
请看一下JSON:顶层有3个键class
,location
和statusTracker
。所有 3 个键的值都是字典,没有数组。
由于class
(小写(是一个保留字,所以我使用 components
.顺便说一下,请遵守结构名称以大写字母开头的命名约定。
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) }
看起来你以错误的方式对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 非常匹配的中间模型,让 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
}
}