#json #swift #decode
Вопрос:
Я использую этот код для вызова своей веб-службы rest. Но если я попытаюсь расшифровать результат вызова веб — службы, я получу ошибку.
class func callPostServiceReturnJson(apiUrl urlString: String, parameters params : [String: AnyObject]?, parentViewController parentVC: UIViewController, successBlock success : @escaping ( _ responseData : AnyObject, _ message: String) -> Void, failureBlock failure: @escaping (_ error: Error) -> Void) {
if Utility.checkNetworkConnectivityWithDisplayAlert(isShowAlert: true) {
var strMainUrl:String! = urlString "?"
for dicd in params! {
strMainUrl.append("(dicd.key)=(dicd.value)amp;")
}
print("Print Rest API : (strMainUrl ?? "")")
let manager = Alamofire.SessionManager.default
manager.session.configuration.timeoutIntervalForRequest = 120
manager.request(urlString, method: .get, parameters: params)
.responseJSON {
response in
switch (response.result) {
case .success:
do{
let users = try JSONDecoder().decode(OrderStore.self, from: response.result.value! as! Data)
}catch{
print("errore durante la decodifica dei dati: (error)")
}
if((response.result.value) != nil) {
success(response as AnyObject, "Successfull")
}
break
case .failure(let error):
print(error)
if error._code == NSURLErrorTimedOut {
//HANDLE TIMEOUT HERE
print(error.localizedDescription)
failure(error)
} else {
print("nnAuth request failed with error:n (error)")
failure(error)
}
break
}
}
} else {
parentVC.hideProgressBar();
Utility.showAlertMessage(withTitle: EMPTY_STRING, message: NETWORK_ERROR_MSG, delegate: nil, parentViewController: parentVC)
}
}
Это ошибка, которую я могу распечатать:
Could not cast value of type '__NSDictionaryI' (0x7fff86d70b80) to 'NSData' (0x7fff86d711e8).
2021-09-27 16:34:49.810245 0200 ArrivaArrivaStore[15017:380373] Could not cast value of type '__NSDictionaryI' (0x7fff86d70b80) to 'NSData' (0x7fff86d711e8).
Could not cast value of type '__NSDictionaryI' (0x7fff86d70b80) to 'NSData' (0x7fff86d711e8).
CoreSimulator 732.18.6 - Device: iPhone 8 (6F09ED5B-8607-4E47-8E2E-A89243B9BA90) - Runtime: iOS 14.4 (18D46) - DeviceType: iPhone 8
Я создал класс OrderStore.swift из https://app.quicktype.io/
Комментарии:
1. Ну, вы понимаете, в чем ошибка?
2. да, но я не знаю, как я могу это исправить
3. Это означает , что
response.result.value
это aDictionary
, а не aData
, если это действительно линия, вызывающая сбой (предоставление этого помогло бы). Вы используетеresponseJSON{}
, такresponse.result.value
же как и словарь или массив, такJSONSerialization
как он уже был вызван в нем. Используйтеresponse.result.data
, если я правильно помню. Если это работает, то используйте метод Alamofire, который позволяет декодировать непосредственно в вашу кодируемую структуру (избегая ненужного уже вызова JSONSeriallization).
Ответ №1:
.responseJSON
возвращает десериализованный JSON, в данном случае a Dictionary
. Это не может быть приведено к Data
тому, что ясно подтверждает ошибка.
Чтобы получить необработанные данные, вам необходимо указать .responseData
Заменять
.responseJSON {
response in
switch (response.result) {
case .success:
do {
let users = try JSONDecoder().decode(OrderStore.self, from: response.result.value! as! Data)
с
.responseData {
response in
switch response.result {
case .success(let data):
do {
let users = try JSONDecoder().decode(OrderStore.self, from: data)
Учтите, что AF 5 поддерживает даже .responseDecodable
декодирование непосредственно в модель
.responseDecodable {
(response : DataResponse<OrderStore,AFError>) in
switch response.result {
case .success(let users): print(users)
Примечания:
- Как упоминалось в вашем предыдущем вопросе
AnyObject
, в API AF его нет. Параметры являются[String:Any]
иresponseData
являются декодированным типом. Я рекомендую сделать функцию универсальной и использовать удобныйResult
тип. - Удалите
break
заявления. Это быстро.
Комментарии:
1. Спасибо за ваш ответ, но ошибка та же самая. Я добавляю в свой вопрос тип (пусть данные)
2. Если вы замените код точно так, как было предложено, та же ошибка возникнуть не может.
3. Я использую ваш код .Данные ответа, но теперь это ошибка: ошибка durante la decodifica dei dati: соответствие типов(ArrivaArrivaStore. ДЖОННулл, Свифт. Ошибка декодирования. Контекст(Путь к кодированию: [Кодовые ключи(значение строки: «результат», значение: ноль), _JSONKey(значение строки: «Индекс 1», значение: 1), Кодовые ключи(значение строки: «time_booking», значение: ноль)], Описание отладки: «Неправильный тип для JSONNull», ошибка в основе: ноль))
4. Это другая ошибка, ошибка декодирования. Это говорит о том, что во втором элементе массива
result
тип свойстваtime_booking
неверен.5. time_booking не является обязательным, поле может содержать это поле и не может содержать его. В моем классе OrderStore.swift объявлен так: let timeBooking: JSONNull?
Ответ №2:
Это дополнение к ответу Вадиана. Я пытаюсь проиллюстрировать процесс, который привел вас к этой ошибке, в надежде, что вы сможете заметить ее в будущем, прежде чем она собьет вас с пути
Это довольно распространенный «шаблон» ошибок.
Представьте себе, что вы идете по лабиринту, отталкиваясь от некоторого исходного формата данных и пытаясь добраться до некоторого целевого формата данных. В каждой точке пути есть несколько вариантов на выбор, некоторые из которых приближают вас к вашей цели, а некоторые уводят вас все дальше.
Вы решили войти в лабиринт у входа , который называется responseJSON
, обратный вызов которого даст вам a AFDownloadResponse<Any>
(который является предполагаемым типом переменной, которую вы вызвали response
).
Структуры JSON всегда имеют массив или словарь на верхнем уровне. Поскольку Alamofire не может статически знать, с каким типом JSON вы будете иметь дело, он моделирует это с помощью an Any
. Во время выполнения типом Value
будет либо NSDictionary
(или один из его конкретных подклассов, например __NSDictionaryI
), либо NSArray
(или один из его конкретных подклассов).
Затем вы решаете воспользоваться result
этим response
. Его статический тип таков Result<Any, Error>
. Вы исправили switch
эту ошибку, убедившись, что имеете дело с success
делом, а не с failure
делом. Необъяснимо, но вы игнорируете значение полезной нагрузки, связанное с успехом, но позже заставляете его развернуть result.response.value!
.
result.response.value
является an Any
, но чтобы успокоить компилятор вашей силой-приведите его к a Data
. Но мы уже знаем , что это будет только NSArray
NSDictionary
операция, так что это никогда не сработает.
Вы могли бы продолжать блуждать в этой части лабиринта и, спотыкаясь, идти к конечной цели по длинному пути. Например, вы можете принудительно привести NSDictionary
, а затем повторно сериализовать эту структуру словаря обратно в строку JSON, в которую вы можете превратиться Data
, только для того , чтобы затем передать ее JSONDecoder().decode
, которая затем декодирует этот JSON обратно. Конечно, все это ужасно запутанно и расточительно. Проблема заключалась в том, что responseJSON
вход в лабиринт не подходил для того места, куда вы пытаетесь попасть!
Вместо этого вы могли бы войти во вход в responseData
лабиринт, который приведет вас прямо к месту Data
назначения!
Хотя тогда вы могли бы понять, что Data
это все время было отвлекающим маневром. На самом деле ты этого не хотел Data
. Вы хотели расшифровать an OrderStore
, и Data
именно так, по вашему мнению, вам нужно было туда попасть. Но оказалось, что так много людей входили через Data
вход с намерением расшифровать какой-то JSON, что люди из Alamofire вырезали новый вход только для вас: responseDecodable
. Это приведет вас прямо к тому OrderStore
, и вы будете возиться с JSON Data
или чем-то еще под капотом, где вам не придется беспокоиться об этом.