Преобразовать userInfo [AnyHashable: Any] в [String: Any] - PullRequest
0 голосов
/ 06 января 2019

Я получил уведомление в didreceiveRemoteNotification, но не могу привести userInfo к словарю типа [String: Any]

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    let dict = userInfo as! [String: Any]
    if let response = dict["message"] as? [String: Any], let baseResponse = Mapper<NotificationModel>().map(JSON: response) {
      //do some stuff
    }
}

когда я пытаюсь разыграть dict ["message"] как! [Строка: Любая] ошибка происходит, и это говорит:

Не удалось привести значение типа «__NSCFString» (0x1cfa84f90) к «NSDictionary» (0x1cfa85bc0).

Вот dict ["message"], когда я печатаю его в консоли:

▿ Optional<Any>
  - some : {"sender":

{"avatar_url":"http:\/\/api.moneyar.com\/APIs\/images\/15783070400.jpg","user_id":"15783","name":"mahdi moqadasi"}

,"conversation_id":"15783"

,"message_id":103597,

"time":1546778745,

"type":1,"message":"foo"

}

Ответы [ 2 ]

0 голосов
/ 06 января 2019

Для следующего ответа код не тестируется на компиляторе, возможно, существует некоторая проблема с опечатками, которую можно легко исправить, некоторые из них намеренно сделаны, чтобы вызвать логику, лежащую в основе, и не добавляются с помощью if let / guard let, as? и т. Д., Которые необходимы, но добавляют шум в объяснение.

Я не буду повторять @ vadian ответ , что является правильным объяснением, почему оно терпит неудачу.

Итак, нам ясно, что dict["message"] это String.

Часть информации, которая, по-видимому, отсутствует в аббревиатуре JSON, предназначена для обозначения "N": нотация.

Когда вы печатали dict["message"], у вас действительно не было объекта ключ / значение, у вас есть строка, представляющая объект ключ-значение, но не в представлении Swift. Вы напечатали JSON Stringified (потому что он явно более удобен для чтения, чем шестнадцатеричные данные JSON). Если после ответа вы напечатаете jsonDict, вы увидите, что структура вывода может отличаться.

Итак, как всегда, ваши основные инструменты:

Data <== data(encoding:)/init(data:encoding:) ==> String
Data <== jsonObject(with:options:)/data(withJSONObject:options:) ==> Array or Dictionary //I bypass voluntarily the specific case of String at top level

Давай сделаем это тогда!

let jsonStringifiedString = dict["message"] as String
let jsonStringifiedData = jsonStringifiedString.data(using: .utf8) as Data
let jsonDict = try JSONSerialization.jsonObject(with: jsonStringifiedData, options: []) as [String: Any]
let baseResponse = Mapper<NotificationModel>().map(JSON: jsonDict)

На вашем месте я бы посмотрел на Mapper, если бы не было способа сделать что-то вроде:

let baseResponse = Mapper<NotificationModel>().map(JSONData: jsonStringifiedData)

или

let baseResponse = Mapper<NotificationModel>().map(JSONString: jsonStringifiedString)

Поскольку иногда в JSON встроены JSONStringified, где вам может потребоваться вызвать его на String или Data напрямую. Или просто потому, что базовый запрос URLSession возвращает объект Data при его закрытии, и вы хотите использовать его напрямую.

0 голосов
/ 06 января 2019

Ошибка

Не удалось привести значение типа «__NSCFString» (0x1cfa84f90) к «NSDictionary» (0x1cfa85bc0).

ясно. Значение ключа message представляет собой строку

  • типа - это real type
  • - - ожидаемое значение неверное тип

if let response = dict["message"] as? String, ...
...