在iOS用户信息上使用Swift的可解码

在iOS用户信息上使用Swift的可解码,swift,apple-push-notifications,codable,decodable,Swift,Apple Push Notifications,Codable,Decodable,iOS从后台通知返回json数据,类型为[AnyHashable:Any]。 有没有办法将其解析为实现可编码协议的结构 例如: // Server sends the following data via apn {"items": [{"id": "192e7926-7891-44eb-8ca7-f795d8552e84", "text": "some text", "num"

iOS从后台通知返回json数据,类型为[AnyHashable:Any]。 有没有办法将其解析为实现可编码协议的结构

例如:

// Server sends the following data via apn
{"items": [{"id": "192e7926-7891-44eb-8ca7-f795d8552e84", "text": "some text", "num": 0.7}]}
在eapp侧接收数据时

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
   print(userInfo["items"])
}
print语句提供以下输出

Optional(<__NSSingleObjectArrayI 0x283fe80b0>(
  {
    id = "192e7926-7891-44eb-8ca7-f795d8552e84";
    num = "0.7";
    text = "Check test";
  }
))
我是否可以从userInfo[items][0]中实例化一个项目?显然,仅仅发送一个编码的json字符串就可以解决这个问题,但我感兴趣的是,是否有一种方法可以将[AnyHashable:Any]解码为可解码的结构


谢谢

您可以使用JSONSerialization.datawithJSONObject将dict转换为JSON对象:

您可能需要一个容器结构

struct ItemsCollection: Decodable {
    let items: [Item]
}
编辑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实例


没有什么可解码的。你收到的不是JSON,而是一本字典。你当然可以把一本字典变成一个条目,但不是通过可解码的方式。所以在它被解码之前,必须先将它编码成数据?我希望swift有一些聪明的魔法,可以利用现有的结构,只进行类型转换。它允许使用可解码对象对数据进行解码,但实际上无法解码字典:您拥有的是类型的dict[AnyHashable:Any]您可以使用此选项,也可以如上文所示,使用提供的默认init来初始化struct的各个属性:请不要建议在DecodingError上下文中使用printerror.localizedDescription。您将得到一条毫无意义的通用错误消息。相反,总是打印错误和预打印在机器级别是毫无意义的。@vadian:Ohhh我没有意识到错误的问题。解码上下文中的localizedDescription将改变它:您的pretty printed point也有意义,同意选项参数可以完全省略。好,如果在没有编码和解码的情况下无法将userInfo类型转换为所需的结构,那么我同意这似乎是无效的。但是通过这种方法,我引入了一个新的地方,如果我已经拥有和使用的结构发生了变化,那么就需要进行更改。我认为以字符串形式发送json可能是最容易维护和最有效的解决方案。谢谢你的回答!最好给项目一个带字典的初始值设定项。@matt这真是个聪明的主意,谢谢@马特:对,已经实施,谢谢。
        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)
        }
        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)
}