Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Swift's Decodable on iOS userInfo

iOS returns json data from background notifications with the type [AnyHashable : Any]. Is there any way to parse that into an struct that implements the Codable protocol?

example :

// Server sends the following data via apn
{"items": [{"id": "192e7926-7891-44eb-8ca7-f795d8552e84", "text": "some text", "num": 0.7}]}

When receiving the data on th eapp side

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
   print(userInfo["items"])
}

the print statement give sthe following output

Optional(<__NSSingleObjectArrayI 0x283fe80b0>(
  {
    id = "192e7926-7891-44eb-8ca7-f795d8552e84";
    num = "0.7";
    text = "Check test";
  }
))

I already have a matching Codable struct:

struct Item: Codable {
    let id: UUID
    let text: String
    let num: Double
}

Can I somehow instantiate an Item from a userInfo["items"][0]? Obviously just sending an encoded json string would already solve that but I'm interested if there is a way to decode from [AnyHashable : Any] into an Decodable struct.

Thanks!

like image 281
lenny Avatar asked Oct 24 '25 14:10

lenny


1 Answers

You can convert the dict to JSON object using JSONSerialization.data(withJSONObject:

You might need a container struct

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)
        }

EDIT 1: You can always optimize the solution by avoiding the creation of new struct using

        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)
        }
like image 178
Sandeep Bhandari Avatar answered Oct 26 '25 04:10

Sandeep Bhandari



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!