我正在尝试使用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和程序设计的初学者,所以如果这是一个愚蠢的问题,请您抽出宝贵的时间。
答案 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))
}