I am unable to get Data Dictionary from Firebase push notification .
My Code :
class func parseIncommingMessages(notification:UNNotification) {
print("PushNotifications: \n \(notification.request.content.userInfo.debugDescription)")
let userInfo = notification.request.content.userInfo as! [String: Any]
let dicDataContainer = userInfo["gcm.notification.data"] as? [AnyHashable:Any]
// notification
if let dicDataMain = dicDataContainer?["Data"] as? [String:Any] , let notificationType = dicDataContainer?["notificationType"] as? String
{
print("\nData: \(dicDataMain)")
print("\n NotificationType: \(notificationType)")
}
}
PushNotifications:
[AnyHashable("gcm.message_id"): 0:1544560847941727%a27b0018a27b0018, AnyHashable("google.c.a.e"): 1, AnyHashable("gcm.notification.data"): {"Data":{"Name":"a","message":"test","operation":"change"},"notificationType":"status_change"}, AnyHashable("aps"): {
alert = {
body = Somthing;
title = Somthing;
};
}]
I am unable to parse , please help me....
You can try
let str = userInfo["gcm.notification.data"] as! String
let res = try? JSONDecoder().decode(Root.self,data:str.data(using:.utf8)!)
print(res?.data)
struct Root : Decodable {
let data: DataClass
let notificationType: String
}
struct DataClass : Decodable {
let name, message, operation: String
}
Related
I'm getting a notification from server side and I'm trying to get data from it, My payload is this:
[AnyHashable("title"): New message received, AnyHashable("gcm.notification.data"): {"FilePath":null,"IsAttachment":false,"UserName":"Muhammad Hassan","User":null,"StrUnPublishDate":null,"Message":"Eggshells","UserImage":"http:\/\/gigjobsadmin.arhamsoft.com\/Content\/User\/36\/16-04-2019 11-460.jpg","User1":null,"ToUserID":null,"ToUserId":132,"SenderId":null,"IsRead":false,"Code":null,"StrPublishDate":null,"StrDateTime":null,"Type":null,"Active":null,"StrCreatedDate":null,"ThreadId":46,"Search":null,"FromUserId":36,"CreatedDate":"2019-06-10T23:00:43.5972809Z","Id":1109,"BatchCount":0}, AnyHashable("gcm.message_id"): 0:1560171729408562%3724072637240726, AnyHashable("data"): {"FilePath":null,"IsAttachment":false,"UserName":"Muhammad Hassan","User":null,"StrUnPublishDate":null,"Message":"Eggshells","UserImage":"http:\/\/gigjobsadmin.arhamsoft.com\/Content\/User\/36\/16-04-2019 11-460.jpg","User1":null,"ToUserID":null,"ToUserId":132,"SenderId":null,"IsRead":false,"Code":null,"StrPublishDate":null,"StrDateTime":null,"Type":null,"Active":null,"StrCreatedDate":null,"ThreadId":46,"Search":null,"FromUserId":36,"CreatedDate":"2019-06-10T23:00:43.5972809Z","Id":1109,"BatchCount":0}, AnyHashable("body"): Eggshells, AnyHashable("badge"): 1, AnyHashable("google.c.a.e"): 1, AnyHashable("aps"): {
alert = {
body = Eggshells;
title = "New message received";
};
badge = 1;
category = ".MainActivity";
"content-available" = 1;
}]
When i get aps from it, it works fine but when i try to gata from "data" key it shows me nil. This is how am i getting values,
let delegate = UIApplication.shared.delegate as! AppDelegate
let userInfo = delegate.userInfo
print(userInfo!)
let data = userInfo!["data"] as? NSDictionary
let message = data!["Message"] as? String
let userImage = data!["UserImage"] as? String
let fromUserId = data!["FromUserId"] as? Int
let createdDate = data!["CreatedDate"] as? String
guard
let aps = userInfo![AnyHashable("aps")] as? NSDictionary,
let alert = aps["alert"] as? NSDictionary,
let body = alert["body"] as? String,
let title = alert["title"] as? String
else {
// handle any error here
return
}
guard let badge = userInfo![AnyHashable("badge")] as? Int
else
{
return
}
The value for key data is a JSON String, not a dictionary. You have to deserialize it separately
struct NotificationData : Decodable {
let message : String
let userImage : URL
let fromUserId : Int
let createdDate : String
private enum CodingKeys: String, CodingKey { case message = "Message", userImage = "UserImage", fromUserId = "FromUserId", createdDate = "CreatedDate" }
}
let delegate = UIApplication.shared.delegate as! AppDelegate
guard let userInfo = delegate.userInfo as? [String:Any],
let notificationString = userInfo["data"] as? String else { return }
let data = Data(notificationString.utf8)
do {
let result = try JSONDecoder().decode(NotificationData.self, from: data)
let message = result.message
let userImage = result.userImage
let fromUserId = result.fromUserId
let createdDate = result.createdDate
} catch { print(error) }
Replace
let data = userInfo!["data"] as? NSDictionary
To
if let data = userInfo!["data"] as? [AnyHashable, Any]{
print(data)
}
I am currently learning Swift and I decided to make an iOS messaging app using Firebase. I am using JSQMessageViewController as my chat template and everything is working fine except for the fact that the app crashes when two users talking to each other are in the chat room at the same time. I am getting this error near the bottom of the function below: "Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)"
Here is my code for observing and retrieving message data. I call this everytime the view appears:
private func observeMessages() {
messageRef = ref.child("ChatRooms").child(chatRoomId!).child("Messages")
let messageQuery = messageRef.queryLimited(toLast:25)
newMessageRefHandle = messageQuery.observe(.childAdded, with: { (snapshot) in
let messageData = snapshot.value as! Dictionary<String, AnyObject>
if let data = snapshot.value as? [String: AnyObject],
let id = data["sender_id"] as? String,
let name = data["name"] as? String,
let text = data["text"] as? String,
let time = data["time"] as? TimeInterval,
!text.isEmpty
{
if id != uid! {
let updateRead = ref.child("ChatRooms").child(self.chatRoomId!).child("Messages").child(snapshot.key)
updateRead.updateChildValues(["status":"read"])
}
if let message = JSQMessage(senderId: id, senderDisplayName: name, date: Date(timeIntervalSince1970: time), text: text)
{
self.messages.append(message)
self.finishReceivingMessage()
}
}else if let id = messageData["senderId"] as! String!,
let photoURL = messageData["photoURL"] as! String! { // 1
if let mediaItem = JSQPhotoMediaItem(maskAsOutgoing: id == self.senderId) {
self.addPhotoMessage(withId: id, key: snapshot.key, mediaItem: mediaItem)
if photoURL.hasPrefix("gs://") {
self.fetchImageDataAtURL(photoURL, forMediaItem: mediaItem, clearsPhotoMessageMapOnSuccessForKey: nil)
}
}
}else {
print("Error! Could not decode message data")
}
})
updatedMessageRefHandle = messageRef.observe(.childChanged, with: { (snapshot) in
let key = snapshot.key
//I am getting an error on this line
let messageData = snapshot.value as! Dictionary<String, String>
if let photoURL = messageData["photoURL"] as String! {
// The photo has been updated.
if let mediaItem = self.photoMessageMap[key] {
self.fetchImageDataAtURL(photoURL, forMediaItem: mediaItem, clearsPhotoMessageMapOnSuccessForKey: key)
}
}
})
}
Curious to what I might be doing wrong here. All help is appreciated!
I need to access the work data which is inside an array of dictionaries and I'm a little bit confuse with this. I'm using swift 3. Some one can give-me some piece of coding to make it done?
I'm using this
let work: NSArray! = fbData.value(forKey: "work") as! NSArray
if let position: NSArray = work[0] as! NSArray {
let positionName: String = position.value(forKey: "name") as! String
self.userWorkExpLabel.text = "\(positionName)" as String
}
but I'm having this answer:
Could not cast value of type '__NSDictionaryI' (0x1106c7288) to 'NSArray' (0x1106c6e28).
there's the API
{
"work": [
{
"employer": {
"id": "93643283467",
"name": "Oracast"
},
"location": {
"id": "111983945494775",
"name": "Calgary, Alberta"
},
"position": {
"id": "146883511988628",
"name": "Mobile Developer"
},
"start_date": "2017-04-30",
"id": "1446626725564198"
}
],
Ok guys. I tried what you posted and what I have now is something like this:
a structs class:
import Foundation
struct Worker{
let employer: Employer
let location: Location
let position: Position
let startDate:String
let id: String
init?(fromDict dict: Dictionary<String, Any>){
guard let employer = Employer(fromDict: dict["employer"] as? Dictionary<String, String>),
let location = Location(fromDict: dict["location"] as? Dictionary<String, String>),
let position = Position(fromDict: dict["position"] as? Dictionary<String, String>),
let startDate = dict["start_date"] as? String,
let id = dict["id"] as? String else {
return nil
}
self.employer = employer
self.location = location
self.position = position
self.startDate = startDate
self.id = id
}
}
struct Employer{
let id: String
let name: String
init?(fromDict dict:Dictionary<String, String>?){
guard let id = dict?["id"],
let name = dict?["name"] else{
return nil
}
self.id = id
self.name = name
}
}
struct Location {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"],
let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
struct Position {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"],
let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
Ive created a class called facebookGraphRequest.
import Foundation
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
import FBSDKShareKit
class facebookGraphRequest: NSObject {
class func graphRequestWork(completion: #escaping(_ error: Error?, _ facebookUserWork: Worker)-> Void){
if ((FBSDKAccessToken.current()) != nil){
let parameters = ["fields": "name, picture.width(198).height(198), location{location}, work{employer}, education, about, id"]
let graphRequest: FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: parameters)
graphRequest.start { (connection, result, error) in
if ((error) != nil ){
print(error!)
}else {
print(result!)
func workersArray(data:Dictionary<String, Any>)->[Worker]?{
guard let arrayOfDict = data["work"] as? Array<Dictionary<String, Any>> else {
return nil
}
return arrayOfDict.flatMap({ Worker(fromDict: $0)})
}
}
}
}
}
}
and I'm calling this data inside the viewController with:
func facebookLogin(){
facebookGraphRequest.graphRequestWork { (error: Error?, facebookUserWork: Worker) in
self.userNameJobPositionLabel.text = "\(facebookUserWork.position)"
self.companyNameLabel.text = "\(facebookUserWork.employer)"
}
}
Somebody knows what's happening? There's nothing happening with the labels.
I thought this apis was easier than that. I'm really confused with this process... Sorry if it looks like stupid questions but I'm really messing my mind because of this things... I really need your help guys. My work depends on that :(
After experimenting with Swift 4 and going in the direction that #PuneetSharma demonstrated I found it's even easier when you use raw JSON text, Codable, and JSONDecoder:
import Foundation
// define the nested structures
struct Work: Codable {
let work: [Worker]
}
struct Worker: Codable {
let employer: Employer
let location: Location
let position: Position
let startDate: String
let id: String
// needed a custom key for start_date
enum CodingKeys : String, CodingKey {
case employer, location, position, startDate = "start_date", id
}
}
struct Employer: Codable {
let id: String
let name: String
}
struct Location: Codable {
let id: String
let name: String
}
struct Position: Codable {
let id: String
let name: String
}
// turn the text into `Data` and then
// decode as the outermost structure
if let jsonData = json.data(using: .utf8),
let work = try? JSONDecoder().decode(Work.self, from: jsonData) {
print(work)
}
The result is a Work structure with all the data:
Work(work: [
Model.Worker(employer : Model.Employer(id : "93643283467",
name: "Oracast"),
location : Model.Location(id : "111983945494775",
name: "Calgary, Alberta"),
position : Model.Position(id : "146883511988628",
name: "Mobile Developer"),
startDate: "2017-04-30",
id : "1446626725564198")
])
(I formatted the output a bit to clarify the structures produced.)
You get a lot of functionality for free just by using Codable. It's also simple to go the other way and produce JSON text from any of the structures.
You should ideally introduce model classes like this:
struct Worker {
let employer:Employer
let location:Location
let position:Position
let startDate:String
let id:String
init?(fromDict dict:Dictionary<String, Any>) {
guard let employer = Employer(fromDict: dict["employer"] as? Dictionary<String, String>), let location = Location(fromDict: dict["location"] as? Dictionary<String, String>), let position = Position(fromDict: dict["position"] as? Dictionary<String, String>), let startDate = dict["start_date"] as? String, let id = dict["id"] as? String else {
return nil
}
self.employer = employer
self.location = location
self.position = position
self.startDate = startDate
self.id = id
}
}
struct Employer {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"], let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
struct Location {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"], let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
struct Position {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"], let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
Now, you can introduce a function like this:
func workersArray(data:Dictionary<String, Any>)->[Worker]?{
guard let arrayOfDict = data["work"] as? Array<Dictionary<String, Any>> else {
return nil
}
return arrayOfDict.flatMap({ Worker(fromDict: $0)})
}
Use this code
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
if let workArray = json["work"] as? [[String: Any]] {
if let dictWork = workArray.first {
if let dictPosition = dictWork["position"] as? [String: String] {
print("position name : \(dictPosition["name"])")
}
}
}
}
I am receiving the GCM Json encoded data as AnyObject as below
[MsgKey: {"NamKey":"Bdy","MobKey":"9964120147","UidKey":"Uid31"}, collapse_key: do_not_collapse, from: 925652137353]
I want to decode the above and pass it to local notication screen
I tried below :
func application(appPsgVar: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
{
print("Notification: ",userInfo["MsgKey"]!)
let MsgVar = userInfo["MsgKey"]
var GotVar = MsgVar?.objectAtIndex(2)
|Or|
var GotVar = MsgVar?.objectForKey("UidKey")
|Or|
var GotVar = MsgVar?.valueForKey("UidKey")
and
if let MsgVar = userInfo["MsgKey"] as? [String:AnyObject]
{
GetNfnFnc(MsgVar["NamKey"] as! String)
}
and
if let MsgVar = userInfo["MsgKey"] as? NSData
{
var JsnAryVar: AnyObject!
do
{
JsnAryVar = try NSJSONSerialization.JSONObjectWithData(MsgVar, options: [])
print(JsnAryVar)
}
catch
{
print("ErrVar")
}
GetNfnFnc(JsnAryVar["NamKey"] as! String)
}
}
userInfo["MsgKey"] gives me below data and not able understand how to decode further
{"NamKey":"Bdy","MobKey":"9964120147","UidKey":"Uid31"}
Actu the problem was Json encoded data from server was coming as String
Method 1: Suggested by Eric D giving the solution link
Retrieving values from 2D array in JSON string
do
{
if let MsgCodVar = MsgSrgVar.dataUsingEncoding(NSUTF8StringEncoding),
let MsgJsnVar = try! NSJSONSerialization.JSONObjectWithData(MsgCodVar, options: []) as? [String:AnyObject]
{
print(MsgJsnVar)
}
}
Method 2 : My own hard workaround :-(
Create own function to convert String data to array[String:AnyObject]
func CnvJsnSrgTooAryFnc(JsnSrgPsgVar: String) -> [String:AnyObject]
{
var JsnSrgVar = JsnSrgPsgVar
JsnSrgVar = JsnSrgVar.stringByReplacingOccurrencesOfString("\"", withString: "")
JsnSrgVar = JsnSrgVar.stringByReplacingOccurrencesOfString("{", withString: "")
JsnSrgVar = JsnSrgVar.stringByReplacingOccurrencesOfString("}", withString: "")
let SrgAryVar = JsnSrgVar.componentsSeparatedByString(",")
var JsnAryVar = [String:AnyObject]()
for SrgIdxVar in SrgAryVar
{
let SrgIdxAryVar = SrgIdxVar.componentsSeparatedByString(":")
JsnAryVar[SrgIdxAryVar[0]] = SrgIdxAryVar[1]
}
return JsnAryVar
}
let MsgAryVar = CnvJsnSrgTooAryFnc(MsgSrgVar)
MsgAryVar["UidKey"]
Got output :
print(MsgSrgVar) :
{"NamKey":"Bdy","MobKey":"9964120147","UidKey":"Uid99"}
print(MsgAryVar)
["NamKey": Bdy, "MobKey": 9964120147, "UidKey": Uid99]
In your third approach, set the JsnAryVar type to a Dictionary ([String: AnyObject]) and cast the result of JSONObjectWithData to a Dictionary.
Follows:
var JsnAryVar: [String: AnyObject]!
JsnAryVar = try NSJSONSerialization.JSONObjectWithData(MsgVar, options: []) as! [String: AnyObject]
Now, you can access the elements inside MsgKey as a Dictionary, like JsnAryVar["NamKey"].
Having trouble which is probably so minor but my searches turn up nothing. I have a json model as follows :
//quick syntax to give you an idea of the model
{user:
{"name": "",
"password": "",
"medium" : {
{"title":"",
{"description":""}}}
I'm getting the above data model from a GET request to user and it returns all the info above but when i try to parse the "medium" information such as "title" & "description" I'm having no luck. I get these responses in Xcode that say
"Value of object 'AnyObject' not unwrapped, did you mean to use ! or ?"
and then when i click on the round red Xcode message to fix it it places !s and ?s everywhere but the error remains. Here is my parse method which worked perfectly fine when I was parsing only from the "medium". Any idea what I'm doing wrong?
a portion of the parse method where i get the same error for each attribute:
all lines with the same error indicated by *
// Parse JSON data
let jsonMedium = jsonResult?["user"] as! [AnyObject] //media where user is
for jsonMedia in jsonMedium {
let media = Media()
*media.title = jsonMedia["medium"]["title"] as! String
*media.description = jsonMedia["medium"]["description"] as! String
*media.category = jsonMedia["medium"]["category"] as! String
*media.image = jsonMedia["medium"]["image"] as! String
*if let IDer = jsonMedia["medium"]["id"] as? Int{
var stringIder = String(IDer)
media.identifierString = stringIder
}
Still no luck with anything. I don't understand why it works with regular JSON but Xcode won't accept anything when I try to obtain nested. All of your help has been appreciated. In the meantime here's the full method if it helps any further
func parseJsonData(data: NSData) -> [Media] {
var medium = [Media]()
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data,
options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
// Parse JSON data
let jsonMedium = jsonResult?["media"] as! [AnyObject]
for jsonMedia in jsonMedium {
let media = Media()
media.title = jsonMedia["medium"]["title"] as! String
media.description = jsonMedia["medium"]["description"] as! String
media.category = jsonMedia["medium"]["category"] as! String
media.image = jsonMedia["medium"]["image"] as! String
if let IDer = jsonMedia["medium"]["id"] as? Int{
var stringIder = String(IDer)
media.identifierString = stringIder
}
medium.append(media)
}
} catch {
print(error)
}
return medium
}
let json = [
"user" : [
"name" : "My Name",
"password" : "My Password",
"medium" : [
"title" : "My Title",
"description" : "My Description"
]
]
]
if let userJson = json["user"] as? [String : AnyObject] {
if let name = userJson["name"] as? String {
print("name: \(name)")
}
if let password = userJson["password"] as? String {
print("password: \(password)")
}
if let mediumJson = userJson["medium"] as? [String : AnyObject] {
if let title = mediumJson["title"] as? String {
print("title: \(title)")
}
if let description = mediumJson["description"] as? String {
print("description: \(description)")
}
}
}
Maybe it helps
let request : ASIFormDataRequest = ...your request
if request.responseString() != nil {
var jsonResponse : Dictionary<String, AnyObject>?
do{
jsonResponse = try NSJSONSerialization.JSONObjectWithData(request.responseData(), options: NSJSONReadingOptions.AllowFragments) as? Dictionary<String, AnyObject>
} catch _ {
//some error
}
}
FIXED IT! Took an entire day of deep thought and google/youtube/stack/brainstorming and your help but it was one changed line that got the whole thing going
// Parse JSON data
let jsonMedium = jsonResult?["user"]!["medium"] as? [AnyObject]
for jsonMedia in jsonMedium! {
let media = Media()
media.title = jsonMedia["title"] as! String
media.description = jsonMedia["description"] as! String
instead of :
let jsonMedium = jsonResult?["user"] as! [AnyObject] //media where user is
for jsonMedia in jsonMedium {
let media = Media()
*media.title = jsonMedia["medium"]["title"] as! String
*media.description = jsonMedia["medium"]["description"] as! String