将 userInfo [AnyHashable: Any] 转换为 [String: Any]

Convert userInfo [AnyHashable: Any] to [String: Any]

我在 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"] 转换为! [String: Any] 错误发生,它说:

无法将“__NSCFString”类型的值 (0x1cfa84f90) 转换为 'NSDictionary' (0x1cfa85bc0)。

这是我在控制台中打印的字典["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"

}

错误

Could not cast value of type '__NSCFString' (0x1cfa84f90) to 'NSDictionary' (0x1cfa85bc0).

很清楚。键message的值是一个字符串

  • 类型真实类型
  • 是预期的错误类型

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

对于以下答案,代码未针对编译器进行测试,可能存在一些可以轻松修复的错字问题,其中一些是故意完成的,以体现其背后的逻辑,而不是添加 if let/guard letas? 等是需要的,但在解释中增加了噪音。

我不会重复 ,这是正确的并解释它失败的原因。

所以我们很清楚dict["message"]是一个String.

您似乎在 JSON 首字母缩略词中遗漏的一条信息代表 "N":表示法。

当您打印 dict["message"] 时,您并没有真正的 key/value 对象,您有一个表示键值对象的字符串,但不是 Swift 表示形式。您打印了 JSON 字符串化(因为它显然比十六进制数据 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)

因为有时 JSONStringified 嵌入 JSON,您可能需要在 StringData 上直接调用它。 或者只是因为基本 URLSession 在其闭包中请求 returns 一个 Data 对象,而您想直接使用它。