Итак, я пытаюсь построить модель, которая будет отвечать за URLRequest
s и синтаксический анализ Decodable
s. Ответ, поступающий от сервера, имеет ту же форму в самом высоком диапазоне, включая ключи status
, page_count
и results
.
results
значения меняются относительно request
, page_count
является необязательным, а status
- это просто String
, указывающее, было ли request
успешным или нет.
Я пытался реализовать сам Generics
в method
и базу Decodable
struct
с именем APIResponse
, а ниже - пример только одной конечной точки с именем extList
. Код компилируется, однако во время выполнения он выдает
Thread 7: Fatal error: 'try!' expression unexpectedly raised an error:
Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "results",
intValue: nil), Swift.DecodingError.Context(codingPath: [],
debugDescription: "No value associated with key
CodingKeys(stringValue: \"results\", intValue: nil) (\"results\").",
underlyingError: nil))
в строке json = try! JSONDecoder().decode(APIResponse<T>.self, from: data)
class NetworkManager {
typealias completion<T: Decodable> = (Result<APIResponse<T>, Error>)->()
class func make<T: Decodable>(of type: T.Type,
request: API,
completion: @escaping completion<T>){
let session = URLSession.shared
var req = URLRequest(url: request.url)
req.httpMethod = request.method
req.httpBody = request.body
session.dataTask(with: req) { (data, response, error) in
if let error = error {
completion(.failure(error))
return
}
var json: APIResponse<T>
if let data = data,
let response = response as? HTTPURLResponse?,
response?.statusCode == 200 {
switch request {
case .extList:
json = try! JSONDecoder().decode(APIResponse<T>.self, from: data)
default:
return
}
completion(.success(json))
}
}.resume()
}
}
Вот база struct
struct APIResponse<T: Decodable>: Decodable {
var status: String
var page_count: Int?
var results: T
}
Вот ответ, который должен заполнить ключ results
в APIResponse
для этой конечной точки.
struct UserResponse: Decodable {
var name: String
var extens: Int
}
Я делаю свой запрос как NetworkManager.make(of: [UserResponse].self, request: .extList) { (result) in ; return }
, и он работает, когда я отбрасываю тип Response
generi c в APIResponse
напрямую с Array<UserResponse>
.
По запросу, образец json
Я пытаюсь декодировать
{
"status": "ok-ext_list",
"page_count": 1,
"results": [
{
"name": "some name",
"extens": 249
},
{
"name": "some other name",
"extens": 245
}
]
}
Есть идеи, как это исправить?
МИНИМАЛЬНЫЙ ВОСПРОИЗВОДИМЫЙ ПРИМЕР
Итак, приведенный ниже код работает, и я совершенно не знаю почему.
JSON s
import Foundation
var extListJSON : Data {
return try! JSONSerialization.data(withJSONObject: [
"status": "ok_ext-list",
"page_count": 1,
"results": [
[
"name": "some name",
"extens": 256
],
[
"name": "some other name",
"extens": 262
]
]
], options: .fragmentsAllowed)
}
var extListString: Data {
return """
{
"status": "ok-ext_list",
"page_count": 1,
"results": [
{
"name": "some name",
"extens": 249
},
{
"name": "some other name",
"extens": 245
}
]
}
""".data(using: .utf8)!
}
Менеджер и служба
enum Service {
case extList
}
class NetworkManager {
typealias completion<T: Decodable> = (APIResponse<T>) -> ()
class func make<T: Decodable>(of type: T.Type, request: Service, completion: completion<T>) {
let data = extListString
let json: APIResponse<T>
switch request {
case .extList:
json = try! JSONDecoder().decode(APIResponse<T>.self, from: data)
}
completion(json)
}
}
Декодируемые
struct APIResponse<T: Decodable>: Decodable {
var status: String
var page_count: Int?
var results: T
}
struct UserResponse: Decodable {
var name: String
var extens: Int
}
Наконец вызов метода
NetworkManager.make(of: [UserResponse].self, request: .extList) { (result) in
dump(result)
}
Опять же, я понятия не имею, почему это работает. Я просто удалил сетевую часть, и она начала работать. Напоминаем, что мой исходный код тоже работает, если я просто использую отдельный Decodable
для каждого request
- без использования Generic
struct
-. Generic
make(:_)
тоже работает нормально.