在 iOS userInfo 上使用 Swift 的 Decodable
Using Swift's Decodable on iOS userInfo
iOS returns json 来自类型为 [AnyHashable : Any]
的后台通知的数据。
有没有办法将其解析为实现 Codable 协议的结构?
示例:
// Server sends the following data via apn
{"items": [{"id": "192e7926-7891-44eb-8ca7-f795d8552e84", "text": "some text", "num": 0.7}]}
app端接收数据时
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
print(userInfo["items"])
}
打印语句给出以下输出
Optional(<__NSSingleObjectArrayI 0x283fe80b0>(
{
id = "192e7926-7891-44eb-8ca7-f795d8552e84";
num = "0.7";
text = "Check test";
}
))
我已经有匹配的 Codable 结构:
struct Item: Codable {
let id: UUID
let text: String
let num: Double
}
我能以某种方式从 userInfo["items"][0]
实例化 Item
吗?显然,只要发送一个编码的 json 字符串就可以解决这个问题,但我很感兴趣是否有一种方法可以将 [AnyHashable : Any] 解码为 Decodable
结构。
谢谢!
您可以使用 JSONSerialization.data(withJSONObject:
将字典转换为 JSON 对象
您可能需要一个容器结构
struct ItemsCollection: Decodable {
let items: [Item]
}
let dict: [AnyHashable: Any] = your dict
do {
let jsonData = try JSONSerialization.data(withJSONObject: dict)
let itemsCollection = try JSONDecoder().decode(ItemsCollection.self, from: jsonData)
//now access it as itemsCollection.items[0]
}
catch {
print(error)
}
编辑 1: 您始终可以通过避免使用
创建新结构来优化解决方案
let dict: [AnyHashable: Any] = userInfo["items"][0] //not sure if you would need explicit type casting here, cant debug as I dont have actual object
do {
let jsonData = try JSONSerialization.data(withJSONObject: dict)
let item = try JSONDecoder().decode(Item.self, from: jsonData)
//now access item
}
catch {
print(error)
}
解码已经反序列化的对象效率不高。
提取数据并创建结构实例手动
struct Item {
let id: UUID
let text: String
let num: Double
init?(dictionary: [String:Any]) {
guard let id = dictionary["id"] as? String,
let uuid = UUID(uuidString: id),
let text = dictionary["text"] as? String,
let num = dictionary["num"] as? Double else { return nil }
self.id = uuid
self.text = text
self.num = num
}
}
if let items = userInfo["items"] as? [[String:Any]],
let firstItem = items.first,
let item = Item(dictionary: firstItem) {
print(item)
}
iOS returns json 来自类型为 [AnyHashable : Any]
的后台通知的数据。
有没有办法将其解析为实现 Codable 协议的结构?
示例:
// Server sends the following data via apn
{"items": [{"id": "192e7926-7891-44eb-8ca7-f795d8552e84", "text": "some text", "num": 0.7}]}
app端接收数据时
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
print(userInfo["items"])
}
打印语句给出以下输出
Optional(<__NSSingleObjectArrayI 0x283fe80b0>(
{
id = "192e7926-7891-44eb-8ca7-f795d8552e84";
num = "0.7";
text = "Check test";
}
))
我已经有匹配的 Codable 结构:
struct Item: Codable {
let id: UUID
let text: String
let num: Double
}
我能以某种方式从 userInfo["items"][0]
实例化 Item
吗?显然,只要发送一个编码的 json 字符串就可以解决这个问题,但我很感兴趣是否有一种方法可以将 [AnyHashable : Any] 解码为 Decodable
结构。
谢谢!
您可以使用 JSONSerialization.data(withJSONObject:
您可能需要一个容器结构
struct ItemsCollection: Decodable {
let items: [Item]
}
let dict: [AnyHashable: Any] = your dict
do {
let jsonData = try JSONSerialization.data(withJSONObject: dict)
let itemsCollection = try JSONDecoder().decode(ItemsCollection.self, from: jsonData)
//now access it as itemsCollection.items[0]
}
catch {
print(error)
}
编辑 1: 您始终可以通过避免使用
创建新结构来优化解决方案 let dict: [AnyHashable: Any] = userInfo["items"][0] //not sure if you would need explicit type casting here, cant debug as I dont have actual object
do {
let jsonData = try JSONSerialization.data(withJSONObject: dict)
let item = try JSONDecoder().decode(Item.self, from: jsonData)
//now access item
}
catch {
print(error)
}
解码已经反序列化的对象效率不高。
提取数据并创建结构实例手动
struct Item {
let id: UUID
let text: String
let num: Double
init?(dictionary: [String:Any]) {
guard let id = dictionary["id"] as? String,
let uuid = UUID(uuidString: id),
let text = dictionary["text"] as? String,
let num = dictionary["num"] as? Double else { return nil }
self.id = uuid
self.text = text
self.num = num
}
}
if let items = userInfo["items"] as? [[String:Any]],
let firstItem = items.first,
let item = Item(dictionary: firstItem) {
print(item)
}