将 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<NotificationModel>().map(JSON: response)
:Mapper
有办法处理(NS)Data
或(NS)String
JSON 吗?因为那应该避免转型。我希望对于更高级别的第三个库它确实如此。是这样吗?喜欢Mapper<NotificationModel>().map(JSONString: jsonStringified)
或Mapper<NotificationModel>().map(JSONData: jsonData)
你在用这个吗:github.com/lyft/mapper/blob/master/Sources/Mapper.swift?
@Larme 是的。我只是将 jsonDict 转换为 [String: Any] 并将其交给 Mapper,它成功地给了我一个模型
【参考方案1】:
对于以下答案,代码未针对编译器进行测试,可能存在一些可以轻松修复的错字问题,其中一些是故意执行其背后的逻辑,而不是添加if let
/ guard let
、as?
等是必需的,但在解释中添加了噪音。
我不会重复@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 中,您可能需要直接在 String
或 Data
上调用它。
或者只是因为基本的URLSession
请求在其闭包中返回了一个Data
对象,而您想直接使用它。
【讨论】:
【参考方案2】:错误
无法将“__NSCFString”(0x1cfa84f90) 类型的值转换为“NSDictionary”(0x1cfa85bc0)。
很清楚。键message
的值是一个字符串
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]的主要内容,如果未能解决你的问题,请参考以下文章
无法使用“Any?”类型的索引为“[AnyHashable:Any]”类型的值下标
错误:键入 [AnyHashable: Any]?没有下标成员 (Swift)
无法访问 [AnyHashable:Any] 类型的值 - Swift 4