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

Posted

技术标签:

【中文标题】将 userInfo [AnyHashable: Any] 转换为 [String: Any]【英文标题】:Convert userInfo [AnyHashable: Any] to [String: Any] 【发布时间】:2019-01-06 12:48:38 【问题描述】:

我在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)。

当我在控制台中打印时,这里是 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"


【问题讨论】:

根据错误似乎dict["message"]是一个String,一个JSON Stringified。所以应该是if let jsonStringified = dict["message"] as? String。我不使用Mapper,而是使用标准工具:伪代码中的let jsonData = jsonStringified.data(encoding: .utf8); let jsonDict = try? JSONSerialization.jsonObject(data: jsonData) @Larme I',去试试你的代码 @Larme 请发表您的评论作为答案。这是正确的。感谢您纠正我 Mapper&lt;NotificationModel&gt;().map(JSON: response)Mapper 有办法处理(NS)Data(NS)String JSON 吗?因为那应该避免转型。我希望对于更高级别的第三个库它确实如此。是这样吗?喜欢Mapper&lt;NotificationModel&gt;().map(JSONString: jsonStringified)Mapper&lt;NotificationModel&gt;().map(JSONData: jsonData) 你在用这个吗:github.com/lyft/mapper/blob/master/Sources/Mapper.swift? @Larme 是的。我只是将 jsonDict 转换为 [String: Any] 并将其交给 Mapper,它成功地给了我一个模型 【参考方案1】:

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

我不会重复@vadian answer,这是正确的解释为什么它失败了。

所以我们很清楚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)

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

【讨论】:

【参考方案2】:

错误

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

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

of type真正的类型 to 是预期的错误类型
if let response = dict["message"] as? String, ...

【讨论】:

这不是答案。我打印 dict["message"] 一切都是键值 @andesta.erfan 你看到的是 JSON,但这不是 Swift 字典的打印方式,所以不是“键值”,现在它只是一个 JSON 字符串。 值肯定是字符串。看来字符串是JSON,你必须单独反序列化它(你实际上对Mapper对象做了什么) 好的。但是“它只是一个 JSON 字符串”是什么意思?以及如何将其转换为 [String: Any] 阅读我对您问题的评论。 JSON 只是一种表示形式。 JSON 中的“N”代表“符号”。这始终是新开发人员缺少的一步。数据表示,字符串表示,最后是序列化后以您自己的语言表示的字典/数组。因此,当在某些 JSON 中嵌入 JSON Stringified 时,就像您的情况一样,解决它的方法总是相同的。

以上是关于将 userInfo [AnyHashable: Any] 转换为 [String: Any]的主要内容,如果未能解决你的问题,请参考以下文章

userInfo 通知数据不可检索?

无法使用“Any?”类型的索引为“[AnyHashable:Any]”类型的值下标

错误:键入 [AnyHashable: Any]?没有下标成员 (Swift)

无法访问 [AnyHashable:Any] 类型的值 - Swift 4

Dictionary<AnyHashable: Any> 在 Swift 3 中 Any 可能持有 nil 值

请求 Facebook 好友返回空