JSON: Extracting Data Using Alamofire and Swift 3 - ios

Can anyone tell me how to get the data out of this JSON?
Here is my code followed by the JSON
let URL = "URL"
Alamofire.request(URL).responseJSON
{ response in
print("HereBegins: = \(response)")
let result = response.result.value as? [String:Any]
}
the json being returned is...
HereBegins: = SUCCESS:
{
items =
(
{
addToCartUrl = "blah blah URL";
affiliateAddToCartUrl = "blah blah another URL";
availableOnline = 0;
brandName = Generic;
bundle = 0;
categoryNode = "976759_1071964_976788";
categoryPath = "Food/Fresh Food/Dairy, Eggs & Cheese/Milk & Cream";
clearance = 0;
customerRating = "5.0";
customerRatingImage = "http://i2.walmartimages.com/i/CustRating/5.gif";
freeShipToStore = 0;
freeShippingOver50Dollars = 1;
giftOptions = {
allowGiftMessage = 0;
allowGiftReceipt = 0;
allowGiftWrap = 0;
};
imageEntities =
(
{
entityType = SECONDARY;
largeImage = "https://i5.walmartimages.com/asr/c2bc3886-fb4f-4c46-b7e9-0cc4ebabc7c1_1.d42acf75b29b132532d5953b139b115f.jpeg?odnHeight=450&odnWidth=450&odnBg=FFFFFF";
mediumImage = "https://i5.walmartimages.com/asr/c2bc3886-fb4f-4c46-b7e9-0cc4ebabc7c1_1.d42acf75b29b132532d5953b139b115f.jpeg?odnHeight=180&odnWidth=180&odnBg=FFFFFF";
thumbnailImage = "https://i5.walmartimages.com/asr/c2bc3886-fb4f-4c46-b7e9-0cc4ebabc7c1_1.d42acf75b29b132532d5953b139b115f.jpeg?odnHeight=100&odnWidth=100&odnBg=FFFFFF";
},
{
entityType = PRIMARY;
largeImage = "https://i5.walmartimages.com/asr/1d575fe6-b8c9-4dc6-821b-42cbde621373_1.4764431b7ebfb4707c0a2f7fe47e85cc.jpeg?odnHeight=450&odnWidth=450&odnBg=FFFFFF";
mediumImage = "https://i5.walmartimages.com/asr/1d575fe6-b8c9-4dc6-821b-42cbde621373_1.4764431b7ebfb4707c0a2f7fe47e85cc.jpeg?odnHeight=180&odnWidth=180&odnBg=FFFFFF";
thumbnailImage = "https://i5.walmartimages.com/asr/1d575fe6-b8c9-4dc6-821b-42cbde621373_1.4764431b7ebfb4707c0a2f7fe47e85cc.jpeg?odnHeight=100&odnWidth=100&odnBg=FFFFFF";
}
);
isTwoDayShippingEligible = 0;
itemId = 46491746;
largeImage = "https://i5.walmartimages.com/asr/1d575fe6-b8c9-4dc6-821b-42cbde621373_1.4764431b7ebfb4707c0a2f7fe47e85cc.jpeg?odnHeight=450&odnWidth=450&odnBg=FFFFFF";
longDescription = "<br><b>Great Value Vanilla Almond Milk, 64 fl oz:</b><br><ul><li>Delicious flavor</li><li>Great Value almond milk comes in a 64 fl oz carton</li><li>Vitamins A, D and E added</li><li>Added calcium</li><li>Only 80 calories per serving</li></ul>";
marketplace = 0;
mediumImage = "https://i5.walmartimages.com/asr/1d575fe6-b8c9-4dc6-821b-42cbde621373_1.4764431b7ebfb4707c0a2f7fe47e85cc.jpeg?odnHeight=180&odnWidth=180&odnBg=FFFFFF";
modelNumber = 11951;
name = "Great Value Vanilla Almond Milk, 64 fl oz";
ninetySevenCentShipping = 0;
numReviews = 3;
offerType = "STORE_ONLY";
parentItemId = 46491746;
preOrder = 0;
productTrackingUrl = "http://linksynergy.walmart.com/fs-bin/click?id=|LSNID|&offerid=223073.7200&type=14&catid=8&subid=0&hid=7200&tmpid=1082&RD_PARM1=https%253A%252F%252Fwww.walmart.com%252Fip%252FGreat-Value-Vanilla-Almond-Milk-64-fl-oz%252F46491746%253Faffp1%253DHzNQqMKL6fuAwFZnu_RUqysY3U3RzuxH0bQKAHNYr0Q%2526affilsrc%253Dapi";
productUrl = "http://c.affil.walmart.com/t/api03?l=https%3A%2F%2Fwww.walmart.com%2Fip%2FGreat-Value-Vanilla-Almond-Milk-64-fl-oz%2F46491746%3Faffp1%3DHzNQqMKL6fuAwFZnu_RUqysY3U3RzuxH0bQKAHNYr0Q%26affilsrc%3Dapi%26veh%3Daff%26wmlspartner%3Dreadonlyapi";
salePrice = "2.58";
shipToStore = 0;
standardShipRate = 0;
stock = "Not available";
thumbnailImage = "https://i5.walmartimages.com/asr/1d575fe6-b8c9-4dc6-821b-42cbde621373_1.4764431b7ebfb4707c0a2f7fe47e85cc.jpeg?odnHeight=100&odnWidth=100&odnBg=FFFFFF";
upc = 078742052366;
}
);
}

Figured it out.
if let resData = result["items"].arrayObject {
arrRes = resData as! [[String:AnyObject]]
for element in arrRes[0]
{
print(element)
}
print(arrRes[0]["name"])

Related

sending parsed JSON data to views

I'm stuck because I can't send JSON data from URLSession func to views. I read the 90% of previous commends and watch lots of videos but I didn't migrate to my project. Here is my code blocks that I need help ;
This ones my json struct
struct APIResponse: Decodable{
let stocks: [Stocks]
}
struct Stocks: Decodable{
let id: Int
let difference: Float
let bid:Float
let isDown: Bool
let isUp: Bool
let offer: Float
let price: Float
let symbol: String
let volume: Double
}
this one is mine JsonDecode code block;
if let data2 = data2 {
do {
// let json = try JSONSerialization.jsonObject(with: data2, options: [])
let apiResponse = try JSONDecoder().decode(APIResponse.self, from: data2)
print(apiResponse.stocks[2].volume)
DispatchQueue.main.async {
completed()
}
}catch{
print(error)
}
}
}.resume()
when I watch videos about it they were [APIResponse].self but when I try that way my code is failed, in my way json parse is working (I can call like 'apiResponse.stocks[2].id') but I can't send this apiResponse data to views.
example of my JSON file
{
status = {
error = {
code = 0;
message = "";
};
isSuccess = 1;
};
stocks = (
{
bid = "31.5";
difference = "-0.2";
id = 1190;
isDown = 1;
isUp = 0;
offer = "31.6";
price = "31.81";
symbol = "P4jfFAYOTiLEih2Ic+NAkg==";
volume = "801457.5";
},
{
bid = "4.25";
difference = "-0.04";
id = 471;
isDown = 1;
isUp = 0;
offer = "4.26";
price = "4.31";
symbol = "zomIgqEl79jIE+TJ7xV4yQ==";
volume = "349264.21";
},
{
bid = "2.86";
difference = "-0.01";
id = 472;
isDown = 1;
isUp = 0;
offer = "2.87";
price = "2.87";
symbol = "2DlR317+autGo3fiKwNhFA==";
volume = "19279.4";
},
{
bid = 55;
difference = 1;
id = 473;
isDown = 0;
isUp = 1;
offer = "55.25";
price = "56.74";
symbol = "fvo0GQ+pqUmHXwm062Gatw==";
volume = "2647954.25";
}, {
bid = "1.22";
difference = "-0.04";
id = 465;
isDown = 1;
isUp = 0;
offer = "1.23";
price = "1.26";
symbol = "wR/24WChHVRFWZSUW1UdwQ==";
volume = "2206441.67";
}
);
}
First if you want to send your response back to the point from where initiated the API call you need to write completion handler and send your response model with the handler; you can take reference from Closures for Swift.
Also apart from that I noticed few errors in your decodable structure, for example you are expecting 'difference' as float type but the example JSON you have posted contains 'difference' as String and it applies for all your float and double values.
Also it will be a good practice If we will declare all the variable optional in decodable structure as if anytime any parameter won't come in response there won't be any problem in parsing it.

Traverse nsdictionary in swift

I am new to swift.
I have my dictionary as
monthData =
{
"2018-08-10" = {
accuracy = 71;
attempted = 7;
correct = 5;
reward = Bronze;
};
"2018-08-12" = {
accuracy = 13;
attempted = 15;
correct = 2;
reward = "";
};
"2018-08-13" = {
accuracy = 33;
attempted = 15;
correct = 5;
reward = "";
};
"2018-08-14" = {
accuracy = 100;
attempted = 15;
correct = 15;
reward = Gold;
};
"2018-08-16" = {
accuracy = 73;
attempted = 15;
correct = 11;
reward = Silver;
};
"2018-08-21" = {
accuracy = 26;
attempted = 15;
correct = 4;
reward = "";
};
"2018-08-23" = {
accuracy = 46;
attempted = 15;
correct = 7;
reward = "";
};
}
I want to get all the dates for which reward is Gold
Can anyone please help me do that?
What I have tried 'till now is:
for (key,value) in monthData{
let temp = monthData.value(forKey: key as! String) as! NSDictionary
for (key1,value1) in temp{
if((value1 as! String) == "Gold"){
print("keyFINAL \(key)")
}
}
but it outputs the error Could not cast value of type '__NSCFNumber' to 'NSString'
The error occurs because when you are iterating the dictionary you force cast the Int values to String which is not possible
The (highly) recommended Swift way is to use the filter function. This is much more efficient than a loop.
In the closure $0.1 represents the value of the current dictionary ($0.0 would be the key). The result is an array of the date strings.
let data : [String:Any] = ["monthData" : ["2018-08-10": ["accuracy" : 71, "attempted" ... ]]]
if let monthData = data["monthData"] as? [String:[String:Any]] {
let goldData = monthData.filter { $0.1["reward"] as? String == "Gold" }
let allDates = Array(goldData.keys)
print(allDates)
}
The code safely unwraps all optionals.
However if there is only one Gold entry the first function is still more efficient than filter
if let monthData = data["monthData"] as? [String:[String : Any]] {
if let goldData = monthData.first( where: {$0.1["reward"] as? String == "Gold" }) {
let goldDate = goldData.key
print(goldDate)
}
}
In Swift avoid the ObjC runtime (value(forKey:)) and Foundation collection types (NSDictionary) as much as possible.
From the first for in loop, you are getting the NSDictionary in temp variable
"2018-08-16" = {
accuracy = 73;
attempted = 15;
correct = 11;
reward = Silver;
};
So, you should directly check .value(forKey:) on temp and get the value for reward.
You should try it like this
for (key,value) in monthData {
let temp = monthData.value(forKey: key as! String) as! NSDictionary
if(((temp.value(forKey: "reward")) as! String) == "Gold"){
print("keyFINAL \(key)")
}
}
Try and share results
EDIT
Please checkout the answer from vadian for in-depth explanation and pure swift approach to achieve the same.
Thanks

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

How to resolve un-ordered JSON dictionary retrieved from YouTube Api?

I've been stuck on this for a while and cannot think logically how to resolve this, and would like some help.
Basically, I'm using the YouTube api to fetch all the video IDs from a changel. I store each of these IDs in an array, and I loop through its indices, each time calling this: https://developers.google.com/youtube/v3/docs/videos/list
This allows me to get the video duration of each video, where I put it in another array of AnyObjects and convert it to a recognizable format.
Here's the output of my videoIDs array, as I fetch it in groups of 10:
videoIDs = ["173ZNVycdQo", "NztC0z1JNq0", "U2C81DNHw2M", "09XKD2sS60E",
"Wc0cVjv44Xc", "ENKHANzmeh4", "mIW5trLZJcM", "KW0ehzTVo-s",
"1MyVzWIwFs4", "HyTQBpZeJCc"]
The problem is in the for loop as shown here:
for (var j = 0; j < self.videoIDs.count; j++)
{
self.getDurations("https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics,status&id=\(self.videoIDs[j])&key=\(self.apiKey)")
}
And Here's my getDurations function:
func getDurations(urlString: String)
{
let targetURL = NSURL(string: urlString)
performGetRequest(targetURL, completion: { (data, HTTPStatusCode, error) -> Void in
if HTTPStatusCode == 200 && error == nil
{
do
{
self.resultsVideoDurationsDict = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as! Dictionary<NSObject, AnyObject>
print("resultsDict = \(self.resultsVideoDurationsDict)")
let items = self.resultsVideoDurationsDict["items"] as AnyObject!
// Loop through all items and add it to another dictionary
for (var i = 0; i < items.count; i++)
{
self.unformattedDurations.append(items[i])
}
}
catch
{
print(error)
}
}
else
{
print("HTTP Status Code = \(HTTPStatusCode)")
print("Error while loading channel details: \(error)")
}
})
}
At every iteration, the JSON of self.resultsVideoDurationsDict is different, i.e. the order of the video IDs within the videoIDs array does not correspond to the same order of data output from the JSON.
I know that due to time delays in the NSURLSession, some data may be fetched earlier than others.
Is there a way to remedy this to way to ensure my self.unformattedDurations contains the ordered data corresponding to the data in the videoIDs array?
Thanks.
UPDATE:
Here's one possible output of self.resultsVideoDurationsDict:
resultsDict = [etag: "DsOZ7qVJA4mxdTxZeNzis6uE6ck/EfACrkkmn5_QpCjD89FgcTdjxVY", kind: youtube#videoListResponse, items: (
{
contentDetails = {
caption = false;
definition = hd;
dimension = 2d;
duration = PT11M29S;
licensedContent = 0;
};
etag = "\"DsOZ7qVJA4mxdTxZeNzis6uE6ck/7wjJ90GVQP7Bo9GwdX8LfdJ8jdg\"";
id = HyTQBpZeJCc;
kind = "youtube#video";
snippet = {
categoryId = 22;
channelId = UC5ltMmeC4YFaart1SSXdmAg;
channelTitle = "Viet My Television";
description = "";
liveBroadcastContent = none;
localized = {
description = "";
title = "PSCD TIEC QUAN 4";
};
publishedAt = "2016-02-02T17:31:58.000Z";
thumbnails = {
default = {
height = 90;
url = "https://i.ytimg.com/vi/HyTQBpZeJCc/default.jpg";
width = 120;
};
high = {
height = 360;
url = "https://i.ytimg.com/vi/HyTQBpZeJCc/hqdefault.jpg";
width = 480;
};
maxres = {
height = 720;
url = "https://i.ytimg.com/vi/HyTQBpZeJCc/maxresdefault.jpg";
width = 1280;
};
medium = {
height = 180;
url = "https://i.ytimg.com/vi/HyTQBpZeJCc/mqdefault.jpg";
width = 320;
};
standard = {
height = 480;
url = "https://i.ytimg.com/vi/HyTQBpZeJCc/sddefault.jpg";
width = 640;
};
};
title = "PSCD TIEC QUAN 4";
};
statistics = {
commentCount = 0;
dislikeCount = 0;
favoriteCount = 0;
likeCount = 0;
viewCount = 14;
};
status = {
embeddable = 1;
license = youtube;
privacyStatus = public;
publicStatsViewable = 1;
uploadStatus = processed;
};
}
), pageInfo: {
resultsPerPage = 1;
totalResults = 1;
}]
The id of that result is HyTQBpZeJCc, which corresponds to the 9th index of the videoIDs array, not the first index. The first output should be for video ID 173ZNVycdQo. Therefore, different outputs are produced at runtime.

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