Cannot access value through keys in nsdictionary - ios

I am confused what problem is this, my dictionary is:
eventDetails = (WebHandler.sharedInstance.eventsDictionary?.copy())! as! NSDictionary
print("Printing eventdeatails: '\(eventDetails)'")
Printing event details: '{
0 = {
"_id" = 5661958b2c0fee491a9e9e08;
date = "9am - 1pm";
degree = ee;
eventCategory = sports;
eventDescription = "cricket match between east and west wing";
eventPhoto = "";
eventTitle = "cricket match";
location = "west wing hall";
society = "the society that has nothing better to do";
universityId = ucf;
};
3 = {
"_id" = 5661981b69439a6a1b17870e;
date = "8am - 3pm";
degree = ee;
eventCategory = sports;
eventDescription = "football match between batch 13 and 14";
eventPhoto = "";
eventTitle = "football match";
location = "west wing hall";
society = "King KOng";
universityId = ucf;
};
1 = {
"_id" = 566195a72c0fee491a9e9e09;
date = "8am - 3pm";
degree = ee;
eventCategory = sports;
eventDescription = "football match between batch 13 and 14";
eventPhoto = "";
eventTitle = "football match";
location = "west wing hall";
society = "King KOng";
universityId = ucf;
};
2 = {
"_id" = 566195b12c0fee491a9e9e0a;
date = "8am - 3pm";
degree = ee;
eventCategory = entertainment;
eventDescription = "showing the harry potter!";
eventPhoto = "";
eventTitle = "movie showing";
location = "west wing hall";
society = "the society that has nothing better to do";
universityId = ucf;
};
}'
This is how i am getting it from my web handler class. I have set very simple keys 0, 1 , 2, ... just to get easily whenever it is required.
it is printing complete dictionary correctly but whenever i try to access the value it is letting me get those particular values instead i get 'nil'
The structure is i have dict with dict What i have tried uptil now is
let key = "2"
print(eventDetails[key]!) //not working
print(eventDetails["2"]!) // just for confirmation, not working
print(eventDetails["2"]!["_id"]!) // not working
print(eventDetails.valueForKey(idnumber)) // i have doubt on word "key" so i changed it and observed it but not good for me
Please help me suggest me some good read or something where i could find the basics or give me some way out. I am clueless at the moment.
Thanking in advance!

Your dictionary is keyed by integer values, therefore you have to access the dictionary with keys of type NSInteger (or Int). Try:
let key = 2
print(eventDetails[key]!)
print(eventDetails[2]!)

Related

Get sorted list of objects in Firebase based on child value [duplicate]

I am using Firebase and I have had no problems getting data in alphabetical order until recently. I never used queries, I always just used snapshots of data and sorted through them one-by-one. Recently, the data has not been always coming in alphabetical order in the snapVal. How do I make it so I get a snapVal of data sorted alphabetically, like it is in the snapshot from the database?
Real Example: there are 4 messages, id1-id4 (in that order). They contiain the message "1"-"4". The snapshot comes looking correct. But the snapVal (snapshot.value) looks like this:
["id2": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
}, "id4": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
}, "id1": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
}, "id3": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
}]
What the snapshot looks like:
["id1": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
}, "id2": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
}, "id3": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
}, "id4": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
}]
To get the snapVal, I use this:
if let snapVal = snapshot.value as? [String: AnyObject] {
// Comes out of order..
}
To clarify:
Snapshot (this ends up coming out correct):
Snap (CHAT) {
id1 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
};
id2 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
};
id3 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
};
id4 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
};
}
This is the output for print(snapVal.keys) inside if let snapVal = snapshot.value as? [String: AnyObject]:
LazyMapCollection<Dictionary<String, AnyObject>, String>(_base: ["id2": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
}, "id4": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
}, "id1": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
}, "id3": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
}], _transform: (Function))
My Code:
self.firebase.child("Chats").child(chatID).queryOrderedByKey().observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
if let snapVal = snapshot.value as? [String: AnyObject] {
print(snapVal)
for c in snapVal {
print("checking Message as child")
let message = c.value["MESSAGE"] as? String
let fn = c.value["FIRST_NAME"] as? String
let ln = c.value["LAST_NAME"] as? String
let USER_ID = c.value["ID"] as? String
if let userID = USER_ID {
if let msg = message {
if let firstName = fn {
if let lastName = ln {
let username = "\(firstName) \(lastName)"
self.addMessage(userID, text: msg, name: username)
print("Message added! \nMessage Info:")
print("User ID: \(userID)")
print("text: \(msg)")
print("Username: \(username)")
} else {
print("LN did not pass")
}
} else {
print("FN did not pass")
}
} else {
print("Msg did not pass")
}
} else {
print("User ID did not pass")
}
}
}
})
Since you haven't shared the necessary code, I'll assume you're doing something along these lines:
ref!.queryOrdered(byChild: "text").observe(.value, with: { (snapshot) in
print("\(snapshot.value)")
})
When you execute a query on a Firebase location, the data is returned with information about the order of the items according to the query. When you observe a value event, the snapshot contains the keys, the values and the order of the children.
But when you convert request the snapshot.value property, all information has to be converted into a dictionary. The keys and the values of each child survive this conversion, but the information on ordering is lost.
For this reason, you'll have to use the children property of the snapshot to iterate over the children in the correct order:
ref!.queryOrdered(byChild: "text").observe(.value, with: { snapshot in
for child in snapshot.children {
print("child \(child)")
}
})
Solution: After very extensive searching and attempting, the problem still persisted that once the snapshot was converted to a snapVal (snapshot.value), the order often rearranged. My (working) solution:
for child in snapshot.children {
let child = child as! FIRDataSnapshot
if let childVal = child.value as? [String: AnyObject] {
let childMessage = childVal["MESSAGE"] as! String
// more code for each child. This child might be a post of a sort, which you can access properties of in a way like I did in the line above
}
}
Process:
Loop through each child in snapshot
Convert the child to a FIRDataSnapshot so it is not an element
Get the value of the particular child to access properties from
Add in the respective code for the child following NSDictionary principles.
Why this solution is solid
Receiving snapshots in the proper order is very simple. The issue I faced was getting data in the correct order when I got the snapshot.value. This solution fixes that because the values of each child are only accessed when looping through the children of snapshot, which is sorted. This leaves the order of children still in the control of the snapshot.
I also like the snapshot.value approach by using [String: AnyObject] because it is very close to the old functionality of Firebase implementation in Swift: Simple and very clean. I actually think that using NSDictionary in this way is really a way to save time in the long run because it is not verbose in any way.
From my experience with Firebase you cannot guarantee the order that the data is being returned in the snapshot value. Firebase provides a couple of functions that you can add to your reference query though to order and sort the data based on key queryOrderedByKey, value queryOrderedByValue, or child queryOrderedByChild.
From your description it sounds like you may want to use queryOrderedByChild to sort you snapshots correctly.
Here's the documentation on those functions and scroll down to the sort data section. https://firebase.google.com/docs/database/ios/lists-of-data
The problem as you can see is not that Firebase is not giving you the response ordered by as requested, the problem is that you are parsing the response into an Dictionary and Dictionaries are no ordered list. The simplest way to fix it is to order your dictionary using something like this:
self.messages.sortInPlace({ ($0.date.compare($1.date) == NSComparisonResult.OrderedAscending)})
Or a even better way is to add the result directly into an array.
You can find more about this problem in this question in my course, there is a long discussion about it there (https://www.udemy.com/firebase/learn/v4/questions/1341056).
Let me know if that helps you.

Read out specific JSON from NSArray

This is the JSON object I'm getting from the openweathermap - API:
["main": {
humidity = 12;
pressure = 922;
temp = "271.13";
"temp_max" = "171.15";
"temp_min" = "291.15";
}, "name": mycity, "id": 299129219, "coord": {
lat = "92.1211";
lon = "182.1211";
}, "weather": <__NSArrayI 0x1c042e820>(
{
description = "light snow";
icon = 13n;
id = 120;
main = Snow;
},
{
description = mist;
icon = 50n;
id = 722;
main = Mist;
}
)
, "clouds": {
all = 12;
}, "dt": 211, "base": stations, "sys": {
country = XXX;
id = 4891;
message = "0.02221";
sunrise = 1221122112;
sunset = 4343344343;
type = 1;
}, "cod": 100, "visibility": 3200, "wind": {
speed = 3;
}]
Because I like to readout some information (like the current temperature, the weather description, etc.) I tried to use this few lines:
let temperature = (result["main"] as! [String:Double])["temp"]!
The code above is working fine but I got massive problems reading out the description of the first Weather element (called "light snow"):
let description = (result["weather"] as! [String:Any]).first["description"]! //(result should be : "light snow")
... doesn't seems working at all.
So how can I fix this issue?
Thanks a million in advance.
Also used this API :)
This worked for me:
guard let weathersArray = json["weather"] as? [[String: Any]],
let weatherJson = weathersArray.first,
let description = weatherJson["description"] as? String
else { return }
Update: in case you want all the array elements just loop over the weathersArray and get all the descriptions.

How Parse JSON from API [duplicate]

This question already has answers here:
type 'Any' has no subscript members
(2 answers)
Closed 5 years ago.
i know to much ask like this. i already searching but not match with my problems.
oke i will try explain with my code
i have data API Like this
["profile": {
accountId = 58e470a0c50472851060d083;
androidDeviceId = "[\"3453247ddcf3f809\"]";
androidVersion = 21;
appId = (
"c46b4c10-62ce-11e6-bdd4-59e4df4b8410",
"fac915f0-fe2b-11e6-9dfb-55339bd7be35"
);
appVersion = "v5.1.0";
avatar = "https://account.8villages.com/uploads/images/5/1491366164_bnx1t0rudi.jpg";
birthDate = "12/03/1994";
"channel-group" = android;
communityId = 553e09b251906884443eff85;
coordinates = {
coordinates = (
"106.9602383333333",
"-6.249333333333334"
);
type = Point;
};
crop = "";
crops = "<null>";
customerId = 5369bd85cae84d0e03246a7c;
dateSubmitted = {
iso = "2017-04-05T04:20:48.483Z";
timestamp = 1491366048;
};
fullName = "Megi Fernanda";
gender = "Laki-laki";
homeAddress = Payakumbuah;
location = "Kota Payakumbuh";
moderation = {
at = {
iso = "2017-04-05T04:20:48.483Z";
timestamp = 1491366048;
};
by = auto;
status = moderated;
};
skill = "Budidaya pertanian";
state = "Sumatera Barat";
storeType = "";
subdistrict = "Payakumbuh Barat";
totalConversations = {
articles = 0;
forums = 0;
questions = 2;
responses = 0;
storeItems = 1;
};
type = users;
university = "Politeknik Negeri Pertanian Payakumbuh";
}, "accessToken": {
key = "lH5aYvnp2JAZ6zoKQK4mpfsxCI0.";
secret = "yfZfTZbsaVIhKCbksGHQnPcPg9mKtoRAKyvjg_cgMeo.";
}]
i already can got fullName, Addres, Skill State etc
if let profile = json["profile"] as? NSDictionary {
let name = profile["fullName"]
let alamat = profile["Skill"]
}
but i don't know how to get atribut in totalConversation like question, storeItems, points
skill = "Budidaya pertanian";
state = "Sumatera Barat";
storeType = "";
subdistrict = "Payakumbuh Barat";
totalConversations = {
articles = 0;
forums = 0;
questions = 2;
responses = 0;
storeItems = 1;
};
i tried like
let profile = json["profile"]["totalConversation"] as? NSDictionary
error sign : Type 'any?' has no subscript members
You got that error because json["profile"] is Any type and it doesn't have any subscript. So you need to cast json["profile"] to a dictionary, [String: Any] is dictionary type in Swift.
if let profile = json["profile"] as? [String: Any] {
if let totalConversations = profile["totalConversations"] as? [String: Any] {
let questions = totalConversations["questions"] as? Int
}
}

Parsing JSON in swift inconsistent

I'm running into what I believe to be a bug. I have an array of objects returned from a server. However, when pulling values out of them I get inconsistent results. Each of these items are in the same array of the response from server:
When I try to pull the quantity value of this one it returns as in Int:
{
address = "4040 MARKET ST RM 226";
city = PHILADELPHIA;
ln = "AMOXICILLIN 500 MG CAPSULE";
ndc = 57237003105;
npi = 1619912375;
"pharmacy_name" = "GRACE PHARMACY INC";
phone = "(215)895-5594";
price = "8.00";
quantity = 500;
state = PA;
vendor = una;
zip = 19104;
}
However, when I try to pull quantity from this one, it's returned as a String.
{
address = "1826 Chestnut St # 30";
brand = G;
city = Philadelphia;
distance = "0.06";
latitude = "39.951747";
ln = "AMOXICILLIN 500 MG CAPSULE";
longitude = "-75.171154";
"ncpdp_id" = 3969485;
ndc = 65862001705;
"pharmacy_hours_of_operation" = "Open 24 Hours";
"pharmacy_name" = "CVS PHARMACY";
phone = "(215)972-0909";
price = "11.82";
quantity = 30;
state = PA;
vendor = scriptsave;
zip = "19103-4902";
}
Why in the world would this be occurring? Both objects seems to be identical except for some extra values in one.
===
Serializing the JSON like this:
let searchResultsJSON: NSDictionary = try NSJSONSerialization.JSONObjectWithData(jsonData, options: .MutableContainers) as! NSDictionary
Grabbing the values like this:
quantity = formDictionary["quantity"] as? Int
quantityString = formDictionary["quantity"] as? String
====
Here is the JSON:
results = (
{
address = "4040 MARKET ST RM 226";
city = PHILADELPHIA;
ln = "ESOMEPRAZOLE MAG DR 40 MG CAP";
ndc = 13668015510;
npi = 1619912375;
"pharmacy_name" = "GRACE PHARMACY INC";
phone = "(215)895-5594";
price = "74.00";
quantity = 1000;
state = PA;
vendor = una;
zip = 19104;
},
{
address = "1700 Market St";
brand = G;
city = Philadelphia;
distance = "0.22";
latitude = "39.952981";
ln = "ESOMEPRAZOLE MAG DR 40 MG CAP";
longitude = "-75.168431";
"ncpdp_id" = 3985059;
ndc = 00378235193;
"pharmacy_hours_of_operation" = "S(Clsd) M(8a-6p) T(8a-6p) W(8a-6p) T(8a-6p) F(8a-6p) S(9a-12p)";
"pharmacy_name" = "PICKWICK PHARMACY INC";
phone = "(215)563-4860";
price = "241.23";
quantity = 30;
state = PA;
vendor = scriptsave;
zip = "19103-3913";
}
);
So here, quantity in the first one is returned as an Int and as a String in the second one. I beginning to think this is a server side issue...
===
Looking at the JSON in Chrome does confirm that it's an encoding error from the server. Thanks #CouchDeveloper
Apple's API's for JSONSerialization are a bit nasty for usage in Swift.
If your happy to make use of third-party frameworks, SwiftyJSON will help with handling JSON in a type safe manner in swift. It's available as a Cocoapod, using Carthage or even Swift's own package manager.
You can then ensure you get non-nil Integer or String objects like so:
let name = json["name"].stringValue
let number = json["number"].intValue
Or you can handle non-existent values as optionals like so:
let name = json["name"].string
let number = json["number"].int

How to index into Array of Dictionaries

I have an object that looks like this in the console. It seems like an array with a dictionary inside. How can I get to the address field?
Optional((
{
address = "xxxxxxx#gmail.com";
verified = 1;
}
))
The object comes from this object:
<METDocument key: <collection: users, ID: KTsCySacEAiz3eDnf>, fields: {
emails = (
{
address = "xxxxxxx#gmail.com";
verified = 1;
}
);
profile = {
address = {
city = Oslo;
country = nor;
lineOne = "address";
lineTwo = "";
zip = 0264;
};
birthdate = "1985-09-01 23:00:00 +0000";
card = {
last4 = 4242;
verified = 1;
};
filledOut = 1;
gender = Male;
name = {
first = "Elon";
last = "Musk";
};
phone = 911;
validated = 1;
};
}>
I access the emails key by this method:
let emails = users.allDocuments[0].valueForKey("emails")
The content of the object is an optional array.
There are two options:
Safe access:
if let emails = users.allDocuments[0].objectForKey("emails") where emails.count > 0 {
if let address = emails[0]["address"] as? String {
print(address)
}
}
If it's guaranteed that the dictionary in the array and the key address exists:
let emails = users.allDocuments[0].objectForKey("emails")!
let address = emails[0]["address"] as! String

Resources