解码JSON中的嵌套对象

时间:2020-09-21 21:06:29

标签: json swift

我正在尝试使用YouTube JSON API获取一些数据,JSON看起来像这样:

{
  "kind": "youtube#channelListResponse",
  "etag": "AVEF8yG4pQMKfzZjMyy1rfVtFXA",
  "pageInfo": {
    "resultsPerPage": 1
  },
  "items": [
    {
      "kind": "youtube#channel",
      "etag": "LpEHq7VFVl1gDbt97Gf4ObyFn0U",
      "id": "UCBJycsmduvYEL83R_U4JriQ",
      "statistics": {
        "viewCount": "2084223845",
        "commentCount": "0",
        "subscriberCount": "12100000",
        "hiddenSubscriberCount": false,
        "videoCount": "1272"
      }
    }
  ]
}

这是我的代码:

import Foundation
struct StatResponse: Decodable {
    let items: Items
}
struct Items: Decodable {
    var statistics: Stats
}
struct Stats: Decodable {
    let subscriberCount: Double
}
enum APIError: Error {
    case wrongURL
    case decodingError
    case noData
}
extension URL {
    static func url() -> URL? {
        guard let url = URL(string: "https://www.googleapis.com/youtube/v3/channels?part=statistics&id=UCBJycsmduvYEL83R_U4JriQ&key=API_KEY") else {
            return nil
        }
        return url
    }
}
class StatService {
    func getStats(completion: @escaping (Result<Items?,APIError>) -> Void) {
        guard let url =  URL.url() else {
             return completion(.failure(.wrongURL))
        }
          URLSession.shared.dataTask(with: url) {
            data, response, error in
            guard let data = data, error == nil else {
                return completion(.failure(.noData))
            }
            let statResponse = try? JSONDecoder().decode(StatResponse.self, from: data)
            if let statResponse = statResponse {
                completion(.success(statResponse.items))
                } else {
                    return completion(.failure(.decodingError))
            }
        }.resume()
    }
}
class StatsViewModel: ObservableObject {
    @Published private var items: Items?
    var subCount: Double {
        guard let subscriberCount = items?.statistics.subscriberCount else {
            return 0
        }
        return subscriberCount
    }
    func fetchStats() {
        StatService().getStats {
            result in switch result {
            case .success(let Items):
                DispatchQueue.main.async {
                    self.items = Items
                }
            case .failure(_ ):
                print("fail")
            }
        }
    }
}

我不知道出了什么问题,结果为0。我尝试了诸如self.items?.statistics = Items.statistics之类的各种操作,而不是self.items = Items,因为我正在尝试获取要获取的数据处于统计数据之下,但它也无法正常工作,并显示错误消息“可选类型“统计信息?”必须解包为'Stats'类型的值”,而且我不知道该怎么办,我可以在Swift中很容易地获取非嵌套对象,但不能嵌套它们。我一般都是Swift和程序设计的初学者,所以如果这是一个愚蠢的问题,请您抽出宝贵的时间。

1 个答案:

答案 0 :(得分:2)

您的模型类出错,items属性是一个数组,并且您尝试将其解码为对象,请将StatResponse更改为:

struct StatResponse: Decodable {
    let items: [Items]
}

还要在subscriberCount结构上将Stats更改为String:

struct Stats: Decodable {
    let subscriberCount: String
}

然后,您将不得不更改访问数据的方式,因为现在您正在访问数组。您可以使用数组的first属性,该属性将返回and数组的第一个元素,如下所示:

if let item = statResponse.items.first {
    completion(.success(item))
} else {
    return completion(.failure(.decodingError))
}