Swift, dictionary parse error - swift

I'm using an API to get weather condition and the retrieved dict is
dict = {
base = stations;
clouds = {
all = 92;
};
cod = 200;
coord = {
lat = "31.23";
lon = "121.47";
};
dt = 1476853699;
id = 1796231;
main = {
"grnd_level" = "1028.63";
humidity = 93;
pressure = "1028.63";
"sea_level" = "1029.5";
temp = "73.38";
"temp_max" = "73.38";
"temp_min" = "73.38";
};
name = "Shanghai Shi";
rain = {
3h = "0.665";
};
sys = {
country = CN;
message = "0.0125";
sunrise = 1476827992;
sunset = 1476868662;
};
weather = (
{
description = "light rain";
icon = 10d;
id = 500;
main = Rain;
}
);
wind = {
deg = "84.50239999999999";
speed = "5.97";
};
}
If I want the value of humidity, I just use
let humidityValue = dict["main"]["humidity"] and it works.
But the problem is I also want to get the value of description in weather
when I used let dscptValue = dict["weather"]["description"]
it retrieved nil.
How's that? and I notice there are two brackets around weather .I'm not sure whether it is the same with the statement without brackets.
weather = (
{
description = "light rain";
icon = 10d;
id = 500;
main = Rain;
}
);
How to get the value of description?

weather keys contains Array of Dictionary not directly Dictionary, so you need to access the first object of it.
if let weather = dict["weather"] as? [[String: AnyObject]], let weatherDict = weather.first {
let dscptValue = weatherDict["description"]
}
Note: I have used optional wrapping with if let for preventing crash with forced wrapping.

Weather is an array of dictionaries.
dict["weather"][0]["description"]
may give you the expected result.

Related

Cannot set optional value, prints nil

I am working on project that writes to google sheets. I am trying to Unmerge cells. This function works however it unmerges everything in the sheet. This is because it is not setting the .range value. When I print (as seen below) the "test" value all range values are shown accordingly however when I print the "request.unmergeCells?.range" it says nil. I am further confused as I use this exact code elsewhere for a merge command and it loads the values fine (see second snippet of code.)
I have tried for days to resolve this issue with no avail. Any thoughts?
func unmergecell1() {
let request = GTLRSheets_Request.init()
let test = GTLRSheets_GridRange.init()
rowstart = 4
rowend = 100
columnstart = 0
columnend = 100
test.startRowIndex = rowstart
test.endRowIndex = rowend
test.startColumnIndex = columnstart
test.endColumnIndex = columnend
request.unmergeCells?.range = test
request.unmergeCells = GTLRSheets_UnmergeCellsRequest.init()
print("=========unmerge==============")
print(test)
print(request.unmergeCells?.range)
let batchUpdate = GTLRSheets_BatchUpdateSpreadsheetRequest.init()
batchUpdate.requests = [request]
let createQuery = GTLRSheetsQuery_SpreadsheetsBatchUpdate.query(withObject: batchUpdate, spreadsheetId: spreadsheetId)
service.executeQuery(createQuery) { (ticket, result, NSError) in
}
}
func mergecell() {
let request = GTLRSheets_Request.init()
request.mergeCells = GTLRSheets_MergeCellsRequest.init()
let test = GTLRSheets_GridRange.init()
test.startRowIndex = rowstart
test.endRowIndex = rowend
test.startColumnIndex = columnstart
test.endColumnIndex = columnend
request.mergeCells?.range = test
request.mergeCells?.mergeType = kGTLRSheets_MergeCellsRequest_MergeType_MergeRows
let batchUpdate = GTLRSheets_BatchUpdateSpreadsheetRequest.init()
batchUpdate.requests = [request]
let createQuery = GTLRSheetsQuery_SpreadsheetsBatchUpdate.query(withObject: batchUpdate, spreadsheetId: spreadsheetId)
service.executeQuery(createQuery) { (ticket, result, NSError) in
}
}
I think you need to switch these 2 lines:
request.unmergeCells?.range = test
request.unmergeCells = GTLRSheets_UnmergeCellsRequest.init()
The 2nd line initates the unmerge request, and only after you initate it can you add the range to it. So by making it the other way round, as below, it should work.
request.unmergeCells = GTLRSheets_UnmergeCellsRequest.init()
request.unmergeCells?.range = test

How to identify the type of an object?

Here is my JSON response for a particular API.
Case 1
ChallengeConfiguration = {
AnswerAttemptsAllowed = 0;
ApplicantChallengeId = 872934636;
ApplicantId = 30320480;
CorrectAnswersNeeded = 0;
MultiChoiceQuestion = (
{
FullQuestionText = "From the following list, select one of your current or previous employers.";
QuestionId = 35666244;
SequenceNumber = 1;
},
{
FullQuestionText = "What color is/was your 2010 Pontiac Grand Prix?";
QuestionId = 35666246;
SequenceNumber = 2;
}
)
}
The key "MultiChoiceQuestion" returns an array with two questions. So here is my code.
let QuestionArray:NSArray = dict1.objectForKey("ChallengeConfiguration")?.objectForKey("MultiChoiceQuestion") as! NSArray
Case 2
ChallengeConfiguration =
{
AnswerAttemptsAllowed = 0;
ApplicantChallengeId = 872934636;
ApplicantId = 30320480;
CorrectAnswersNeeded = 0;
MultiChoiceQuestion = {
FullQuestionText = "From the following list, select one of your
current or previous employers.";
QuestionId = 35666244;
SequenceNumber = 1;
}
}
For Case 2 my code does not work and app crashes because it returns a dictionary for that specific Key. So how could I write a generic code that would work for all objects?
It looks like the key can contain either an array of dictionary values or a dictionary, so you just need to try casting to see which one you have.
so I would likely do it like this:
if let arr = dict1.objectForKey("ChallengeConfiguration")?.objectForKey("MultiChoiceQuestion") as? Array {
// parse multiple items as an array
} else if let arr = dict1.objectForKey("ChallengeConfiguration")?.objectForKey("MultiChoiceQuestion") as? [String:AnyObject] {
// parse single item from dictionary
}
You should never really use ! to force unwrap something unless you are completely certain that the value exists and is of the type you are expecting.
Use conditional logic here to test the response and parse it safely so that your app doesn't crash, even in failure.

Swift 3: Iterate through a _NSSingleObjectArrayI

I'm fetching data from a weather API. I'm not sure how to access the description?
"weather": <__NSSingleObjectArrayI 0x608000012910>(
{
description = "overcast clouds";
icon = 04n;
id = 804;
main = Clouds;
}
)
I tried:
print(weatherDict["weather"]!.description!)
It just gave me this:
(
{
description = "overcast clouds";
icon = 04n;
id = 804;
main = Clouds;
}
)
How do I properly access the description?
weather contains an array of dictionaries.
description is a key in the first item of the array.
The code unwraps weather safely and checks if the array is not empty:
if let weatherArray = weatherDict["weather"] as? [[String:Any]],
let weather = weatherArray.first {
print(weather["description"]) // the value is an optional.
}

Multidimensional array makes Xcode6 crash

I have an application which retrieves a JSON file. Here you are a piece of my code:
Array definition
var photos: NSArray = []
How I populate the array:
ezJson().createRequest("http://myapiurl/load", type: "GET", params: nil, completion: {(returnedObject : AnyObject?, error : NSError?)in
if returnedObject{
self.photos = returnedObject as NSArray
self.tableView.reloadData()
}
})
println(self.photos)
{
created = {
date = "2014-06-13 18:35:46";
timezone = "Europe/Madrid";
"timezone_type" = 3;
};
description = description1;
id = 3;
name = 539b286277617;
},
{
created = {
date = "2014-06-13 18:38:38";
timezone = "Europe/Madrid";
"timezone_type" = 3;
};
description = description2;
id = 4;
name = 539b290ed8577;
}
println(self.photos[0])
{
created = {
date = "2014-06-13 18:35:46";
timezone = "Europe/Madrid";
"timezone_type" = 3;
};
description = description1;
id = 3;
name = 539b286277617;
}
The problem is, I don't know how to get a particular item. I've tried:
println(self.photos[0]) // it works
println(self.photos[0]["name"] // Xcode crash "Command /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift failed with exit code 254"
println(self.photos[0].name) // returns nil
How can I access to the name parameter ?
It seems that you are casting a String to NSArray. This won't give you the effect that you want.
First of all, if you want to acces your elements by name, you want an NSDictionary.
Then it propably still won't work, as there is no implicit conversion between the types so you will have to either parse it yourself or use some JSON library.
Last : your JSON is incorrect.

UITableView+YouTubeAPI parsing JSON response for statistics

I am getting the JSON response from youtube API v3 for https://www.googleapis.com/youtube/v3/channels?part=statistics&id
and receiving JSON response as
{
etag = "\"rFqCJSkEICLP3Hq6a4AADI7kf48/2zirKmd0WgUqY0RzlyD4hlACeWM\"";
items = (
{
etag = "\"rFqCJSkEICLP3Hq6a4AADI7kf48/u4TmQ5XfIQQg6y6u4Od2yULCVlc\"";
id = "HCcrj0EHvn_Y8";
kind = "youtube#channel";
statistics = {
commentCount = 0;
subscriberCount = 21694;
videoCount = 124582;
viewCount = 0;
};
},
{
etag = "\"rFqCJSkEICLP3Hq6a4AADI7kf48/2p4_mjrZLfhO6bDvH-RgAykNQr8\"";
id = UCX2v47KsDKqajrEYFV7GbBg;
kind = "youtube#channel";
statistics = {
commentCount = 6460;
subscriberCount = 494656;
videoCount = 33;
viewCount = 713607227;
};
}
}
when I am trying to display the
cell.viewsChannel.text=[[_statistics valueForKeyPath:#"statistics.videoCount"] objectAtIndex:indexPath.row];
the value doesn't display on table view.
I tried to format the output as unsigned long ,int but the correct values don't show.
Please help
Thanks in advance
I think you need to add item to valueForKeyPath
cell.viewsChannel.text=[[_statistics valueForKeyPath:#"item.statistics.videoCount"] objectAtIndex:indexPath.row];