我试图用Swift中的可编码解析JSON . 我以前成功完成了这个,但是我有一个更复杂的JSON对象和一些数组,我遇到了麻烦 .
这是我的JSON:
{
"data": [ {
"type":"player",
"id":"account.7e5b92e6612440349afcc06b7c390114",
"attributes": {
"createdAt":"2018-04-06T04:59:40Z",
"name":"bob",
"patchVersion":"",
"shardId":"pc-na",
"stats":null,
"titleId":"bluehole-pubg",
"updatedAt":"2018-04-06T04:59:40Z"
},
"relationships": {
"assets": {
"data":[]
},
"matches": {
"data": [
{"type":"match","id":"3e2a197a-1453-4569-b35b-99e337dfabc5"},
{"type":"match","id":"15f41d2f-9da2-4b95-95ca-b85e297e14b7"},
{"type":"match","id":"a42c496c-ad92-4d3e-af1f-8eaa2e200c2b"}
{"type":"match","id":"b6e33df5-4754-49da-9a0f-144842bfc306"},
{"type":"match","id":"5b357cd1-35fe-4859-a2d7-48f263120bbd"},
{"type":"match","id":"99fc5f81-c24c-4c82-ae03-cd21c94469c0"},
{"type":"match","id":"1851c88e-6fed-48e8-be84-769f20f5ee6f"},
{"type":"match","id":"e16db7ea-520f-4db0-b45d-649264ac019c"},
{"type":"match","id":"6e61a7e7-dcf5-4df5-aa88-89eca8d12507"},
{"type":"match","id":"dcbf8863-9f7c-4fc9-b87d-93fe86babbc6"},
{"type":"match","id":"0ba20fbb-1eaf-4186-bad5-5e8382558564"},
{"type":"match","id":"8b104f3b-66d5-4d0a-9992-fe053ab4a6ca"},
{"type":"match","id":"79822ea7-f204-47f8-ae6a-7efaac7e9c90"},
{"type":"match","id":"1389913c-a742-434a-80c5-1373e115e3b6"}
]
}
},
"links": {
"schema":"",
"self":"https://api.playbattlegrounds.com/shards/pc-na/players/account.7e5b92e6612440349afcc06b7c390114"
}
}],
"links": {
"self":"https://api.playbattlegrounds.com/shards/pc-na/players?filter[playerNames]=dchilds64"
},
"meta":{}
}
以下是我使用的模型:
public struct PlayerResponse: Codable {
let data: [Player]
}
对于玩家:
public struct Player: Codable {
let type: String
let id: String
let attributes: Attributes
let relationships: Relationships
}
对于属性:
public struct Attributes: Codable {
let name: String
let patchVersion: String
let shardId: String
let titleId: String
let updatedAt: String
}
对于关系:
public struct Relationships: Codable {
let matches: Matches
}
对于比赛:
public struct Matches: Codable {
let data: [Match]
}
匹配:
public struct Match: Codable {
let type: String
let id: String
}
解码为:
let players = try decoder.decode([Player].self, from: jsonData)
我有这个运行我的网络请求的功能:
func getPlayerData(for name: String, completion: ((Result<[Player]>) -> Void)?) {
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "api.playbattlegrounds.com"
urlComponents.path = "/shards/\(regionShard.rawValue)/players"
let playerNameItem = URLQueryItem(name: "filter[playerNames]", value: "\(name)")
urlComponents.queryItems = [playerNameItem]
guard let url = urlComponents.url else { fatalError("Could not create URL from components") }
print(url)
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/vnd.api+json", forHTTPHeaderField: "Accept")
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: request) { (responseData, response, responseError) in
DispatchQueue.main.async {
if let error = responseError {
completion?(.failure(error))
} else if let jsonData = responseData {
let decoder = JSONDecoder()
do {
let players = try decoder.decode([Player].self, from: jsonData)
completion?(.success(players))
} catch {
completion?(.failure(error))
}
} else {
let error = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Data was not retrieved from request"]) as Error
completion?(.failure(error))
}
}
}
task.resume()
}
我遇到的问题是当我尝试运行网络请求时出现此错误:
我认为我的可编码结构存在问题,但我不确定 . 有人能指出我正确的方向来寻找我的错误吗?
2 回答
我建议你从地面构建这个,因为
JSONDecoder
(与任何编译器一样)的错误越严重,你的结构就越多 . 让我们看看我们得到了多远:你的
Match
结构非常合理:这里没有意外的问题 . 缩短
Matches
有点你已经得到了第一个错误,而不是意想不到的错误将打印以下错误:
这是一个微不足道的错误,你错过了
data
Array
第3行的逗号 . 添加一切都会顺利,但如果它来自您的服务,您将不得不先修复它 .我想你已经明白了,并且知道如何逐步 Build 这个结构 . 在顶层,您会注意到您的顶级结构超出了
Player
的数组,它实际上是Dictionary
,其中"data"
是唯一的键,因为您在PlayerResponse
中正确建模,因为@AnkitJayaswal已经指出 . 这已经产生了两个错误,那些是我设法轻易发现的错误,但正如我之前建议的那样,你应该继续进行测试的构建,这样你就会知道"lower"级别正确解析并且可以专注于手头的问题 .以上所有操作都可以在Playground中轻松完成,并且无需在此过程中实际调用WebService . 当然你必须
import Cocoa
,但你已经知道了 . 无论如何,通过将问题分成更小的部分总是有助于降低复杂程度 .正如我所看到的,整个玩家的回应都在关键
data
. 你的解析播放器信息直接与Player
可编码结构,而不是data
密钥,它在PlayerResponse
可编码结构中使用 .To resolve this update your code as:
希望这能解决你的问题 .