Parsing JSON in swift inconsistent - ios

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

Related

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

Cannot access value through keys in nsdictionary

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]!)

Indexing into NSArray with JSON object

I receive an object that is sent as a pointer to a collection.
I can access the fields directly as an NSDictionary.
The emails field is sent as an array, and I receive it in parentheses. Currently I get the emailaddress by what I feel is a roundabout method.
How can I most efficiently get to the email address?
let allDoc = users.allDocuments[0]
print("allDoc: \(allDoc)")
let emailsArray = users.allDocuments[0].valueForKey("emails") as! NSArray
print("emailsArray: \(emailsArray)")
let emailAddress = emailsArray[0]["address"] as! String
print("emailAddress: \(emailAddress)")
Console output:
allDoc: <METDocument key: <collection: users, ID: kzzw3vcqukD62xEyz>, fields: {
emails = (
{
address = "xxxx#gmail.com";
verified = 1;
}
);
profile = {
address = {
city = "";
country = nor;
lineOne = "";
lineTwo = "";
zip = "";
};
card = {
last4 = 4242;
verified = 1;
};
filledOut = 1;
name = {
first = XXXX;
last = XXXX;
};
phone = 9999999999;
validated = 1;
};
}>
emailsArray: (
{
address = "xxxx#gmail.com";
verified = 1;
}
)
emailAddress: xxxx#gmail.com
If you just want the email address you could simply do:
let emailsAddress = users.allDocuments[0]["emails"][0][#"address"] as! String
print("emailAddress: \(emailAddress)")
But it really is better to use multiple lines. It makes the code much easier to read and debug. Also, putting all that onto one line doesn't allow any error checking. What if the #"emails" key has an empty array, for example? The code will crash.

Parse Json using SwiftyJson

I am able to get the entire JSon array parsed. It outputs to console with no issue. I can't seem to get the individual params from the array... my json looks like:
[{
City = NYC;
Device = "<null>";
DisplayAs = "Steve Hutson";
FirstName = Steve;
LastName = Hutson;
MobilePhone = "000-000-0000";
Org = "<null>";
Region = "";
Role = INSPECTOR;
SupervisorID = "73990";
email = "email#email.com";
fLast = shutson;
"gz_modtimestamp" = "2015-07-28 14:42:41";
id = 96;
isActive = YES;
lastupdated = "<null>";
sendemail = 1;
token = "<null>";
userpassword = "xxx";
},{
City = DET;
Device = "<null>";
DisplayAs = "Filipe Washington";
FirstName = Filipe;
LastName = Washington;
MobilePhone = "000-000-0000";
Org = "<null>";
Region = "";
Role = INSPECTOR;
SupervisorID = "6567";
email = "email#email.com";
fLast = shutson;
"gz_modtimestamp" = "2015-07-28 13:02:09";
id = 93;
isActive = YES;
lastupdated = "<null>";
sendemail = 1;
token = "<null>";
userpassword = "xxx";
}]
In my main ViewController.swift file my json request looks like:
var myData:NSData = getJSON("http://xxxx/getusersData.php")
var myDict:NSArray = parseJSON(myData)
println(myDict)
This prints my entire json object which is perfect. However my issue is, how do I get only the FirstName's in an array? By index this works:
println(myDict[0]["FirstName"]) how ever, it only brings back one item.
I am trying to insert specific json items into sqlite which i am using SQLite.swift but i need to know how to retrieve specific item parameters as I would if i was using AJAX.
I am trying to retrieve FirstName, Email and UserPassword info.
Any help would be appreciated.
You can iterate over the JSON object and retrieve that info:
for (index: String, subJson: JSON) in json {
//Do something you want
var firstName = subJson["FirstName"].stringValue
var email = subJson["email"].stringValue
var userPassword = subJson["userpassword"].stringValue
// Build the sqlite query with the variables here
}
As a clarification, you don't access the values directly as in json["FirstName"], you must also use the type functions from SwiftyJSON. In your case they're both strings, so stringValue is used. If you needed and int, it'd be intValue.
There's also the option of just json["FirstName"].string in case the field is optional. Take a look at the readme

NSDictionary annidate in swift

I have this json result.
I would take the field "alert".
I try this:
var alert: NSString = jsonResult["features"]["properties"]["alert"]
but this is the error: does not have a member named 'subscript'.
I can not how to access a field in a nested dictionary
{
features = (
{
geometry = {
coordinates = (
"-97.95359999999999",
"37.2382",
5
);
type = Point;
};
id = usb000si7g;
properties = {
alert = green;
cdi = "5.8";
code = b000si7g;
detail = "http://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/usb000si7g.geojson";
dmin = "0.017";
felt = 1258;
gap = 38;
ids = ",usb000si7g,";
mag = "4.3";
magType = mwr;
mmi = "4.94";
net = us;
nst = "<null>";
place = "8km SE of Harper, Kansas";
rms = "0.51";
sig = 864;
sources = ",us,";
status = reviewed;
time = 1412272884590;
title = "M 4.3 - 8km SE of Harper, Kansas";
tsunami = "<null>";
type = earthquake;
types = ",cap,dyfi,general-link,geoserve,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,tectonic-summary,";
tz = "-300";
updated = 1412614943519;
url = "http://earthquake.usgs.gov/earthquakes/eventpage/usb000si7g";
};
type = Feature;
}
);
metadata = {
api = "1.0.13";
count = 1;
generated = 1412617232000;
status = 200;
title = "USGS Significant Earthquakes, Past Week";
url = "http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/significant_week.geojson";
};
type = FeatureCollection;
}
I don't know what to do. swift is changed every beta.
As #Kirsteins said is his answer, you have to do a lot of unwrapping, and it's recommended to use a JSON library.
If you still want to stick with hand made extraction, then I suggest you to made it programmatically, such as adding an extension to NSDictionary as follows:
extension NSDictionary {
func objectForTreeKeys<T>(keys:[String]) -> T? {
var dict: NSDictionary? = self
var retValue: T?
for key in keys {
var value: AnyObject? = dict?.objectForKey(key)
if let unwrapped = value as? NSDictionary {
dict = unwrapped
} else if let unwrapped = value as? T {
retValue = unwrapped
break
} else {
retValue = nil
break
}
}
return retValue
}
}
You pass an array of keys to the function, and it traverses all nested dictionaries until:
a value of type T is encountered
a value having type different than NSDictionary and T is found
a nil value is found
In the first case, it returns the value of T type - in the other cases it returns nil.
You can use it as follows:
let ret: String? = jsonResult.objectForTreeKeys(["features", "properties", "alert"])
As you can see, it's a generic method, and the return type is inferred from the type of the variable the result is assigned to - so it's necessary to explicitly define its type, which must be optional (String? in this specific case).

Resources