簡體   English   中英

如何使用 Codable 和 Swift 解析這個嵌套的 JSON?

[英]How do I parse this nested JSON using Codable with Swift?

我正在嘗試使用 Codable 解析這個 JSON:

{
  "users": [
    {
      "id": 1,
      "name": "Allen Carslake",
      "userName": "acarslake0",
      "profileImage": "https://source.unsplash.com/random/400x400",
      "createdDate": "2019-07-08T00:00:00.000+0000"
    },
    {
      "id": 2,
      "name": "Revkah Antuk",
      "userName": "rantuk1",
      "profileImage": "https://source.unsplash.com/random/400x400",
      "createdDate": "2019-07-05T00:00:00.000+0000"
    },
    {
      "id": 3,
      "name": "Mirna Saffrin",
      "userName": "msaffrin2",
      "profileImage": "https://source.unsplash.com/random/400x400",
      "createdDate": "2019-05-19T00:00:00.000+0000"
    },
    {
      "id": 4,
      "name": "Haily Eilers",
      "userName": "heilers3",
      "profileImage": "https://source.unsplash.com/random/400x400",
      "createdDate": "2019-06-28T00:00:00.000+0000"
    },
    {
      "id": 5,
      "name": "Oralie Polkinhorn",
      "userName": "opolkinhorn4",
      "profileImage": "https://source.unsplash.com/random/400x400",
      "createdDate": "2019-06-04T00:00:00.000+0000"
    }
]
}

我在這里保持 URL 私有,但它在上面返回 JSON。 到目前為止,這是我的代碼:

import UIKit

struct User: Codable {
    let id: Int
    let name: String
    let userName: String
    let profileImage: String
    let createdDate: String
}

struct Users: Codable {
    let users: String
}

let url = URL(string: "")!

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

    if let data = data {

        let users = try? JSONDecoder().decode([User].self, from: data)
        print(users)
    }

    }.resume()

我需要能夠訪問 User 屬性,但我認為嵌套對我來說很困難。 任何幫助都很棒!! 謝謝!!

首先:始終Catch DecodingErrorprint它。 它會准確地告訴您出了什么問題

發生錯誤是因為您忽略了根對象Users 如果您decode(Users.self .

我的建議:

  • createdDate解碼為Date添加適當的日期解碼策略。
  • profileImage解碼為URL (免費)。
  • 處理所有錯誤。

struct Root : Decodable { // `Users` and `User` is too confusing
    let users: [User]
}

struct User : Decodable {
    let id: Int
    let name: String
    let userName: String
    let profileImage: URL
    let createdDate: Date
}

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

    if let error = error { print(error); return }
    do {
        let decoder = JSONDecoder()
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: "en_US_POSIX")
        dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        decoder.dateDecodingStrategy = .formatted(dateFormatter)
        let result = try decoder.decode(Root.self, from: data!)
        for user in result.users {
           print(user.userName, user.id, user.createdDate)
        }
    } catch {
        print(error)
    }

}.resume()

json 的根是字典而不是數組,您可以編寫根類但它沒有用,因此您需要

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

   do {     
    if let data = data { 
        let res = try JSONSerialization.jsonObject(with: data) as! [String:Any]
        let usersData = try JSONSerialization.data(withJSONObject: res["users"])
        let users = try JSONDecoder().decode([User].self, from: usersData) 
        print(users)
    }
   }
   catch {
     print(error)
   }

}.resume()

您的Users結構(我將其重命名為UsersResponse )應該包含一個[User]類型的users屬性。 然后您可以執行以下操作:

struct UsersResponse: Codable {
    let users: [User]
}

URLSession.shared.dataTask(with: url) { data, _, _ in
    guard let data = data else { return }

    if let users = try? JSONDecoder().decode(Users.self, from: data).users {
        users.forEach { user in
            print("A user called \(user.name) with an id of \(user.id).")
        }
    }
}.resume()

請嘗試以下代碼。 這對我有用。

型號分類:

struct UsersResponse: Codable {
   let users: [User]
}

struct User: Codable {
    let id: Int
    let name: String
    let userName: String
    let profileImage: String?
    let createdDate: String
}

網絡類:

public enum EndPoints: String {
    case prod = "ProdURL"
    case test = "testURL"
}

public enum Result<T> {
    case success(T)
    case failure(Error)
}

final public class Networking: NSObject {


// MARK: - Private functions
private static func getData(url: URL,
                            completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
    URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
}

/// fetchUsersResponse function will fetch the User Response and returns
/// Result<UsersResponse> as completion handler

 public static func fetchUsersResponse(shouldFail: Bool = false, completion: @escaping (Result<UsersResponse>) -> Void) {
    var urlString: String?
    if shouldFail {
        urlString = EndPoints.test.rawValue
    } else {
        urlString = EndPoints.prod.rawValue
    }

    guard let mainUrlString = urlString,  let url = URL(string: mainUrlString) else { return }

    Networking.getData(url: url) { (data, response, error) in
        if let error = error {
            completion(.failure(error))
            return
        }

        guard let data = data, error == nil else { return }

        do {
            let decoder = JSONDecoder()

            //decoder.dateDecodingStrategy = .millisecondsSince1970
            decoder.dateDecodingStrategy = .formatted(setDateFormat())

            let json = try decoder.decode(UsersResponse.self, from: data)
            completion(.success(json))
        } catch let error {
            completion(.failure(error))
        }
    }
}

func setDateFormat() -> DateFormatter {
    let dateFormat = DateFormatter()
    dateFormat.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
    return dateFormat
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM