I am trying to parse gcm.notification.createdAt key, but its value is not being casted as Int.
Strangely it is not working even though the value type is clearly Int as you can see.
Any idea what am I doing wrong here?
userInfo is [AnyHashable("gcm.notification.chatUID"): -LgHYXKFNmP-mQo7s9nB,
AnyHashable("gcm.notification.type"): chat,
AnyHashable("gcm.notification.createdAt"): 1559389303,
AnyHashable("google.c.a.e"): 1,
AnyHashable("gcm.message_id"): 0:1559389316529351%e413fc3ee413fc3e,
AnyHashable("aps"): {
alert = {
body = "You have a new message";
title = "New Message from Lehz Raus";
};
badge = 1;
sound = default;
}]
let userInfo = response.notification.request.content.userInfo
guard let createdAt = userInfo["gcm.notification.createdAt"] as? Int else {
print("gcm.notification.createdAt is not showing")
return
}
//this works as expected
guard let chatUUUUID = userInfo["gcm.notification.chatUID"] as? String else {
print("no chatUUUUID printed")
return
}
I suspect your value is not really an Int.
You can investigate the underlying type by printing:
print(type(of: userInfo["gcm.notification.createdAt"]!))
From the comments, you said it returned: __NSCFString so the server is giving you a String. You can convert that to an Int with an additional line in your guard statement:
guard let createdAt = userInfo["gcm.notification.createdAt"] as? String,
let createdAtInt = Int(createdAt) else {
print("gcm.notification.createdAt is not showing")
return
}
Related
Here is my code and it fails to execute as noted below.
I am trying to cast an object to my custom data type called UserData.
First problem I have is don't understand how to get the value out of the array correctly
Second I cannot seem to cast the object as the type I need, UserData. What I am doing wrong?
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
var users = NSMutableArray();
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
for i in 0 ..< jsonResult.count {
print("loop count :", i );
jsonElement = jsonResult[i] as! NSDictionary
let user = UserData()
//the following insures none of the JsonElement values are nil through optional binding
if let UserID = jsonElement["Userid"] as? String,
let firstName = jsonElement["First_Name"] as? String,
let lastName = jsonElement["Last_Name"] as? String,
let userSessionID = jsonElement["Session_ID"] as? String
{
user.UserID = UserID
user.FirstName = firstName
user.LastName = lastName
user.UserSessionID = userSessionID
print("users firstName:", user.FirstName ?? "blank");
}
users.add(user)
}
print("users size:", users.count); // this shows 2
// So i know I have data loaded... BUT when i try and
// get it then it all goes to heck. See below
// NOT SURE what I am doing here...
// Thought it was java like where I could just get a
// item from the NSMutableArray using an index value
// then cast it as my UserData object
// and print the output... but this does not work
// Why is this so hard??
let userDataVal = users.index(of: 0) as! UserData;
print("firstName:", userDataVal.FirstName);
}
Below is how I would write this function. Some comments
No NS... classes used, instead I use native arrays and dictionaries
If JSONSerialization.jsonObject generates an error the function is exited
Local variables are define as close as possible to as where they are used
Create an init method for your UserData struct/class that takes the values as parameters so you can do let user = UserData(userId: UserId, firstName:... instead.
Name local variables and properties with a first lowercase character, it makes it easier to read the code
func parseJSON(_ data:Data) {
var jsonResult: [[String: Any]]?
do {
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as? [[String: Any]]
} catch let error as NSError {
print(error)
return
}
guard let result = jsonResult else {
return
}
var users = [UserData]()
for jsonElement in result {
if let UserID = jsonElement["Userid"] as? String,
let firstName = jsonElement["First_Name"] as? String,
let lastName = jsonElement["Last_Name"] as? String,
let userSessionID = jsonElement["Session_ID"] as? String
{
var user = UserData()
user.UserID = UserID
user.FirstName = firstName
user.LastName = lastName
user.UserSessionID = userSessionID
users.append(user)
}
}
for user in users {
print("firstName:", user.FirstName);
}
}
Better approach would be to use JSONDecoder() instead of a JSONSerailizer. Try using the following code.
struct User: Codable {
var userId, firstName, lastName, userSessionId: String
enum CodingKeys: String, CodingKey {
case userId = "Userid"
case firstName = "First_Name"
case lastName = "Last_Name"
case userSessionId = "Session_ID"
}
}
func parseJSON(_ data: Data) {
do {
let users = try JSONDecoder().decode([User].self, from: data)
users.forEach { user in
print("users first name:", user.firstName)
}
} catch {
print(error.localizedDescription)
}
}
I have this block of code:
func fetchFriends() {
if let window = UIApplication.shared.keyWindow {
guard let userId = Auth.auth().currentUser?.uid else { return }
DispatchQueue.main.async {
FirestoreService.shared.fetchFriendList(userId) { (fetchedFriends) in
//// WONT GET HERE ////
if fetchedFriends != nil {
self.fetchedFriends = fetchedFriends! // Can force unwrap here because we already know that fetchedFriends in not nil.
self.friendsTable.reloadData()
}else {
self.fetchedFriends = []
self.friendsTable.reloadData()
}
}
}
}
}
This block of code is using this function:
func fetchFriendList(_ id: String, completion: #escaping([Friend]?)->()) {
var fetchedFriends: [Friend] = []
db.collection(USERS_COLLECTION).document(id).getDocument { (doc, err) in
if err == nil && doc != nil {
guard let results = doc?.data()?[USER_FOLLOWING] as? [String: Any] else { return }
for result in results { // Getting the data in firebase
if let resultValue = result.value as? [String: Any] { // Getting only the value of the MAP data, we do not need the key.
//Getting the fields from the result
guard let id = resultValue[FRIEND_ID] as? String else { return }
guard let profilePic = resultValue[FRIEND_PROFILE_PIC] as? String else { return }
guard let username = resultValue[FRIEND_NAME] as? String else { return }
guard let email = resultValue[FRIEND_MAIL] as? String else { return }
//Creating a new Friend object from the fields
let friend = Friend(id: id, profilePicture: profilePic, username: username, email: email)
fetchedFriends.append(friend)
}
completion(fetchedFriends)
}
}else {
print(err!.localizedDescription)
completion(fetchedFriends)
}
}
}
Whats happening here, is that I'm going into a user's document, getting it's 'Friends' from a Map I have in the document, creating a Friend Array and sending it in the completion to the first function.
In the first function, I'm checking if what I got is nil, if not, I'm assigning it to an array, else, if it is nil, I want the array to be empty.
The purpose here is to show the "Friends" in the tableView if the user has any.
My problem is this situation:
For start, the list of friends is empty, adding a friend and viewing the list, the friend I just added is showing, which is good. the problem is, when I'm removing this friend from the list (and it is deleted in the Database in Firestore), showing the list again does not deletes him from the list and still showing it.
It seems that after removing a friend from the "following" section, and showing the list again, after FirestoreService.shared... it just returns and won't get to the "Won't get here" line.
The FetchFriends() function does gets called everytime I'm opening the FriendsList.
This is a picture of the list I'm referring to, this demouser is removed from the friends list but still showing up.
EDIT: Just noticed that when I have more than one user on the list, it does gets deleted and it works as I want. When I have just one user (or just one left on the list) it won't delete it.
fetchFriendList never calls the callback with a nil value:
var fetchedFriends: [Friend] = []
Therefore your else branch is unnecessary and the completion handler could be #escaping ([Friend]) -> Void without optionals.
By the way, there is also a situation when your method does not call completion at all:
guard let results = doc?.data()?[USER_FOLLOWING] as? [String: Any] else { return }
In general, there are many unsafe places. For example, when err is nil and doc is nil, then your else will crash unwraping err!.
A better alternative:
guard err == nil, let doc = doc else {
print(err?.localizedDescription)
completion([])
return
}
let results = (doc.data()?[USER_FOLLOWING] as? [String: Any]) ?? [:]
let fetchedFriends = results.compactMap { result in
guard
let resultValue = result.value as? [String: Any],
let id = resultValue[FRIEND_ID] as? String,
let profilePic = resultValue[FRIEND_PROFILE_PIC] as? String,
let username = resultValue[FRIEND_NAME] as? String,
let email = resultValue[FRIEND_MAIL] as? String
else { return nil }
return Friend(id: id, profilePicture: profilePic, username: username, email: email)
}
completion(fetchedFriends)
Hi all I have tried a few solutions but no luck.
I am getting the text from Data Core, but the textview has optional on it.
when it prints it shows optional in the text.
page22TextView?.text = ("\(trans.value(forKey: "page22"))")
can anyone shed light on this ! have tried to unwrap but it stillelow: shows.
the full function is below:
func getTranscriptions () {
//create a fetch request, telling it about the entity
let fetchRequest: NSFetchRequest<TextInputs> = TextInputs.fetchRequest()
do {
//go get the results
let searchResults = try getContext().fetch(fetchRequest)
//I like to check the size of the returned results!
print ("num of results = \(searchResults.count)")
//You need to convert to NSManagedObject to use 'for' loops
for trans in searchResults as [NSManagedObject] {
page22TextView?.text = ("\(trans.value(forKey: "page22"))")
//get the Key Value pairs (although there may be a better way to do that...
print("\(trans.value(forKey: "page22"))")
}
} catch {
print("Error with request: \(error)")
}
}
try to set default value of getting nil value
page22TextView?.text = (trans.value(forKey: "page22") as? String) ?? ""
It'll set your value from trans and if it retrun nill will be set by "".
Hope it'll help you.
try with if-let statement:
if let result = trans.value(forKey: "page22") {
page22TextView?.text = result
}
Or try with guard statement:
guard let result = trans.value(forKey: "page22") else { return }
page22TextView?.text = String(describing: result)
Or you can force upwrap it like:
let result = trans.value(forKey: "page22")
if result != nil {
page22TextView?.text = result! as! String
}
Or you can follow the way suggested by #MrugeshTank below in answers
try to unwrap optional using if let then assign to your textview (if necessary then downcast your value)
if let value = trans.value(forKey: "page22") {
page22TextView?.text = value
}
or
use guard for unwrap
I am new to Swift. I tried with this Swift link Detect a Null value in NSDictionaryNSDictionary, but I failed to do so.
Data:
"end_time" = "<null>"
Here is my code:
if endTime["end_time"] is NSNull {
print("your session still available ")
}
else{
print("your session end \(endTime["end_time"])")
}
Every time it is going to else statement. May be I need to convert string to null or alternative solution. Could you help me please?
Thank you.
Here's how you check null in swift:
let time = endTime["end_time"]
if time != "<null>" {
print("time is not <null>")
}
else
{
print("time is <null>")
}
You can create a NilCheck controller to check nil or null for various datatypes. For example i have created a function to remove null [if any] from the dictionary and store the array of dictionary in Userdefaults. Please be free to ask your queries :)
func removeNilAndSaveToLocalStore(array : [[String:Any]]) {
var arrayToSave = [[String:Any]]()
for place in array {
var dict = [String:Any]()
dict["AreaId"] = NilCheck.sharedInstance.checkIntForNil(nbr: place["AreaId"]! as? Int)
dict["AreaNameAr"] = NilCheck.sharedInstance.checkStringForNil(str: place["AreaNameAr"]! as? String)
dict["AreaName"] = NilCheck.sharedInstance.checkStringForNil(str: place["AreaName"]! as? String)
dict["GovernorateId"] = NilCheck.sharedInstance.checkIntForNil(nbr: place["GovernorateId"]! as? Int)
arrayToSave.append(dict)
}
LocalStore.setAreaList(token: arrayToSave)
}
class NilCheck {
static let sharedInstance : NilCheck = {
let instance = NilCheck()
return instance
}()
func checkStringForNil(str : String?) -> String {
guard let str = str else {
return String() // return default string
}
return str
}
func checkIntForNil(nbr : Int?) -> Int {
guard let num = nbr else {
return 0 // return default Int
}
return num
} }
I am on point where I gotta compare non optional value with nil. But I can't do it because Xcode says:
Comparing non-optional value of type 'Int' to nil always returns false
So I created Struct and then made variable: var products: [Product] = []
How I am able to compare it with nil?:
if products[indexPath.row].snusPortions == nil
{
cell.snusPortionsAmountLabel.text = "N/A"
}else
{
cell.snusPortionsAmountLabel.text = String(products[indexPath.row].snusPortions)
}
I've assigned values to them like this:
let ref = FIRDatabase.database().reference().child("Snuses").queryOrdered(byChild: "Brand").queryEqual(toValue: brandName)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists(){
let enumerator = snapshot.children
while let thisProduct = enumerator.nextObject() as? FIRDataSnapshot
{
print(thisProduct.value) // So I may see what the data is like and know how to extract it
// Chances are you'd have to create a dictionary
let thisProductDict = thisProduct.value as! [String:AnyObject]
let productName = thisProductDict["Products"] as! String
let snusPortions = thisProductDict["PortionsCan"] as? Int
let productObject = Product(snusProductTitle: productName, snusNicotine: snusNicotine, snusPortions: snusPortions!, snusFlavor: snusFlavor, snusWeight: snusWeight!, snusShippingWeight: snusShippingWeight, snusProductImageURL: productURL)
self.products.append(productObject)
print(self.products)
}
self.tableView.reloadData()
}
})
This is Product struct:
struct Product {
var snusProductTitle: String
init()
{
snusProductTitle = ""
}
init(snusProductTitle: String){
self.snusProductTitle = snusProductTitle
}
}
While testing it says snusPortions is nil but I said to make it "N/A" if it is nil, why?
It sounds like you are confusing yourself between the local variable snusPortions and the Product property snusPortions.
In your Product definition, the property snusPortions is an Int. It can never be nil. Hence, in this code:
if products[indexPath.row].snusPortions == nil
... this Product's snusPortions will never be nil, and we will never set the text to "N/A".
Now let's look at your other code:
let snusPortions = thisProductDict["PortionsCan"] as? Int
This is a completely different snusPortions. It can be nil, namely, if thisProductDict lacks a "PortionsCan" key or if its value is not castable to Int.