【问题标题】:I need to create a table view with a nested Json我需要创建一个带有嵌套 Json 的表视图
【发布时间】:2019-02-26 15:11:58
【问题描述】:

我必须从 url 读取一个 json:https://randomuser.me/api/?results=100

我创建了 People.swift 文件,其中包含通过该站点创建的结构:https://app.quicktype.io/?l=swift

我尝试使用此代码,但我无法将 json 插入到结构中,然后通过 cell.people.name 调用它。

ViewController.swift:

var dataRoutine = [People]() // this is the structure that I created with the site indicated above.

这是我下载Json并解析的函数。

func downloadJsonData(completed : @escaping ()->()){

        guard let url = URL(string: "https://randomuser.me/api/?results=100")else {return}
        let request = URLRequest.init(url: url)

        URLSession.shared.dataTask(with: request) { (data, response, error) in

            if let httpResponse = response as? HTTPURLResponse {
                let statuscode = httpResponse.statusCode
                if statuscode == 404{
                    print( "Sorry! No Routine Found")
                }else{
                    if error == nil{
                        do{
                            self.dataRoutine = try JSONDecoder().decode(People.self, from: data!)
                            DispatchQueue.main.async {
                                completed()
                                print(self.dataRoutine.count) // I don't know why my result is ever 1.
                            }
                        }catch{
                            print(error)
                        }
                    }
                }
            }

            }.resume()

    }

我的结构是:

 import Foundation

struct People: Codable {
    let results: [Result]?
    let info: Info?
}

struct Info: Codable {
    let seed: String?
    let results, page: Int?
    let version: String?
}

struct Result: Codable {
    let gender: Gender?
    let name: Name?
    let location: Location?
    let email: String?
    let login: Login?
    let dob, registered: Dob?
    let phone, cell: String?
    let id: ID?
    let picture: Picture?
    let nat: String?
}

struct Dob: Codable {
    let date: Date?
    let age: Int?
}

enum Gender: String, Codable {
    case female = "female"
    case male = "male"
}

struct ID: Codable {
    let name: String?
    let value: String?
}

struct Location: Codable {
    let street, city, state: String?
    let postcode: Postcode?
    let coordinates: Coordinates?
    let timezone: Timezone?
}

struct Coordinates: Codable {
    let latitude, longitude: String?
}

enum Postcode: Codable {
    case integer(Int)
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Int.self) {
            self = .integer(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        throw DecodingError.typeMismatch(Postcode.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Postcode"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .integer(let x):
            try container.encode(x)
        case .string(let x):
            try container.encode(x)
        }
    }
}

struct Timezone: Codable {
    let offset, description: String?
}

struct Login: Codable {
    let uuid, username, password, salt: String?
    let md5, sha1, sha256: String?
}

struct Name: Codable {
    let title: Title?
    let first, last: String?
}

enum Title: String, Codable {
    case madame = "madame"
    case mademoiselle = "mademoiselle"
    case miss = "miss"
    case monsieur = "monsieur"
    case mr = "mr"
    case mrs = "mrs"
    case ms = "ms"
}

struct Picture: Codable {
    let large, medium, thumbnail: String?
}

【问题讨论】:

  • 到底哪里出了问题?

标签: json swift tableview


【解决方案1】:

主要问题是类型不匹配。

JSON 的根对象不是People 数组,它是伞形结构,我将其命名为Response

请将结构更改为

struct Response: Decodable {
    let results: [Person]
    let info: Info
}

struct Info: Decodable {
    let seed: String
    let results, page: Int
    let version: String
}

struct Person: Decodable {
    let gender: Gender
    let name: Name
    let location: Location
    let email: String
    let login: Login
    let dob, registered: Dob
    let phone, cell: String
    let id: ID
    let picture: Picture
    let nat: String
}

struct Dob: Decodable {
    let date: Date
    let age: Int
}

enum Gender: String, Decodable {
    case female, male
}

struct ID: Codable {
    let name: String
    let value: String?
}

struct Location: Decodable {
    let street, city, state: String
    let postcode: Postcode
    let coordinates: Coordinates
    let timezone: Timezone
}

struct Coordinates: Codable {
    let latitude, longitude: String
}

enum Postcode: Codable {
    case integer(Int)
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Int.self) {
            self = .integer(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        throw DecodingError.typeMismatch(Postcode.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Postcode"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .integer(let x):
            try container.encode(x)
        case .string(let x):
            try container.encode(x)
        }
    }
}

struct Timezone: Codable {
    let offset, description: String
}

struct Login: Codable {
    let uuid, username, password, salt: String
    let md5, sha1, sha256: String
}

struct Name: Codable {
    let title: Title
    let first, last: String
}

enum Title: String, Codable {
    case madame, mademoiselle, miss, monsieur, mr, mrs, ms
}

struct Picture: Codable {
    let large, medium, thumbnail: String
}

几乎所有属性都可以声明为非可选的,Dob 中的 date 键是 ISO8601 日期字符串,您必须添加适当的日期解码策略。 People 数组是根对象的属性results

var dataRoutine = [Person]()

func downloadJsonData(completed : @escaping ()->()){

    guard let url = URL(string: "https://randomuser.me/api/?results=100")else {return}

    URLSession.shared.dataTask(with: url) { (data, response, error) in

        if let httpResponse = response as? HTTPURLResponse {
            let statuscode = httpResponse.statusCode
            if statuscode == 404{
                print( "Sorry! No Routine Found")
            }else{
                if error == nil{
                    do{
                        let decoder = JSONDecoder()
                        decoder.dateDecodingStrategy = .iso8601
                        let jsonResponse = try decoder.decode(Response.self, from: data!)
                        self.dataRoutine = jsonResponse.results
                        DispatchQueue.main.async {
                            completed()
                            print(self.dataRoutine.count) // I don't know why my result is ever 1.
                        }
                    }catch{
                        print(error)
                    }
                }
            }
        }

        }.resume()

}

【讨论】:

  • dataRoutine 必须声明为var dataRoutine = [Person]()
  • typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "dob", intValue: nil), CodingKeys(stringValue: "date", intValue: nil)], debugDescription: "预期解码 Double,但找到了一个字符串/数据。",underlyingError: nil)) 现在我有这个错误
  • 请仔细阅读我的回答。您必须添加decoder.dateDecodingStrategy = .iso8601,然后添加decoder.decode...
  • 我做了一点修改。将try JSONDecoder().decode 替换为try decoder.decode
  • 现在如果我只想打印电子邮件,我可以使用 print(self.dataRoutine.email) ?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
  • 2018-09-10
  • 1970-01-01
相关资源
最近更新 更多