Не удалось привести значение типа ‘__NSDictionaryI’

#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 это a Dictionary , а не a Data , если это действительно линия, вызывающая сбой (предоставление этого помогло бы). Вы используете 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 или чем-то еще под капотом, где вам не придется беспокоиться об этом.