I got notification in didreceiveRemoteNotification but I can not cast userInfo to dictionary of type [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
}
}
when I try to cast dict["message"] as! [String: Any] error happens and it says:
Could not cast value of type '__NSCFString' (0x1cfa84f90) to 'NSDictionary' (0x1cfa85bc0).
Here is dict["message"] when I print it in console:
▿ 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"
}
For the following answer, the code is not tested against a compiler, there might be some typo issue that could be easily fixed, some of them are intentionally done to exergue the logic behind it, and not add with if let/guard let, as?, etc. that are needed but add noise in the explanation.
I won't repeat @vadian answer, which is correct an explain why it fails.
So we are clear that dict["message"] is a String.
A piece of information that you seem to be missing in the JSON acronym is for what stands the "N": Notation.
When you printed dict["message"], you didn't have really a key/value object, you have a String representing a key-value object, but not in a Swift representation. You printed JSON Stringified (because it's clearly more readable that hex data JSON). If after the answer you print jsonDict, you'll see that the output structure might be different.
So, as always, your basic tools are:
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's do it then!
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)
If I were you, I'd look into Mapper if there is no way to do something like:
let baseResponse = Mapper<NotificationModel>().map(JSONData: jsonStringifiedData)
or
let baseResponse = Mapper<NotificationModel>().map(JSONString: jsonStringifiedString)
Because there are sometimes JSONStringified embedded in JSON, where you might need to call it on a String or on a Data directly.
Or just because the basic URLSession request returns a Data object in its closure, and you want to use it directly.
The error
Could not cast value of type '__NSCFString' (0x1cfa84f90) to 'NSDictionary' (0x1cfa85bc0).
is clear. The value of key message is a string
if let response = dict["message"] as? String, ...