I have a webservice, in which the parameter "upload_images" have more than one value. How can i get that values. I am using SBJson. Here is my response
{
"node_title": "thk",
"category": "Boating",
"description": "Fg",
"link": "",
"nid": "446",
"post date": "Mon, 11/25/2013 - 07:04",
"upload_images": "http://prod.kyzook.com/?q=sites/prod.kyzook.com/files/styles/medium/public/2013-11-25%2007%3A03%3A25%20%2B0000.png&itok=WIBTqzbC, http://prod.kyzook.com/?q=sites/prod.kyzook.com/files/styles/medium/public/2013-11-25%2007%3A03%3A58%20%2B0000.png&itok=AhoLUnou"
}
If I understand your question correctly, upload_images contains a string of comma-separated URLs and you want to extract them.
You can easily achieve this using NSString's method componentsSeparatedByString, for instance
NSString *uploadImages = response[#"upload_images"];
NSArray *imageURLs = [uploadImages componentsSeparatedByString:#", "];
where I assumed response to be a NSDictionary object holding the parsed response.
you can get the the "upload_images" as the string and can convert in the array using componentsSeparatedByString: method
NSString *uploadImages = [response objectForKey:#"upload_images"];
NSArray *imageUrlArray = [uploadImages componentsSeparatedByString:#", "];
Related
So I was working on a project that required me to work with some JSON, I was running into a few issues regarding the best way of representing things. First of, this is how the JSON looks:
"phoneList": [
{
"phoneReason": "End of Contract",
"phoneType": [
{
"id": 5,
"phoneType": "Android Smartphone"
}
]
}
]
I want to know the most appropriate way of representing this.
For example, I do know that that my phoneReason will just be a simple NSString while my phoneType is actually a NSArray. However,I wasn't sure how to represent a)the id, I know this is an integer, but should this be an NSInteger or an NSNumber and b)could someone point me in the direction of some sample code where I can understand how to model a dictionary object containing an integer and a string and also where I can understand how to model an array of dictionaries.
My other question is also similar in that say I'm actually posting something, how do I model this, specifically say for like dictionary type (JSON Curly Brace)objects that contain a number/integer and a string.
For example, this is the JSON I'm trying to model and then do something like this:
"phoneReason": "Upgrade",
"phoneInfo": {
"id": "2"
},
//And then I want to pass ID
-(void) createOurRequest:(NSNumber *)id {
NSDictionary *myDictionary = #{
#"phoneReason" : [NSString stringWithFormat:#"%i", s elf.dat.reason],
//How do I then represent the phoneInfo element exactly?
};
Sorry, for the clumsy question, would really appreciate any guidance on modeling JSON in iOS or just generally.
I'm assuming you're asking questions a) and b), and also how to model a JSON.
a) The unfortunate thing with Obj-C is that all collection elements have to be objects. Integers are value types, so they will need to be converted to NSNumbers to work. However, if you're parsing a JSON string, the builtin JSON parser does it for you. I'll describe it below.
b) The model is based on the JSON. You describe the object collection and the parser will determine the model for you. In your example, you would have a NSDictionary<NSString *: NSArray<NSDictionary<NSString *: id>*>*>. The innermost element has value of id because you can either have an NSString ("End of Contract") or an NSArray ("phoneType": [ { "id": 5, "phoneType": "Android Smartphone" } ])
Of course, the model is defined by your JSON, so if you run it through a parser, you get a structured object. You can access each element based on your model (object[#"phoneList"][#"phoneReason"]).
The class method to use is:
+ (id)JSONObjectWithData:(NSData *)data
options:(NSJSONReadingOptions)opt
error:(NSError **)error
Where you pass it a NSData representation of your string, options (or 0), and a NSError pointer (error*). You get back a parsed JSON with the proper structure you defined.
NSDictionary *parsedJSONObject = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:NULL
I have no options to use and I know there will be no error, so I pass nothing for those parameters. The resulting object will be in whatever structure your JSON is.
Using the objects and the json layout you provided in your first example, this is how I would go about creating the dictionaries and arrays to get the json in the format you specified. Hopefully this helps make it a little clearer for you.
// example constructor method
-(void) jsonStringWithPhoneReason:(NSString*)reason phoneId:(NSInteger)phoneId phoneType:(NSString*)phoneType
{
// create device detail dictionary
NSDictionary *deviceOneDetail = #{
#"id" : #(phoneId), // <- set phone id as NSNumber
#"phoneType" : phoneType // <- set your string phone type
};
// create device dictionary
NSDictionary *deviceOne = #{
#"phoneReason" : reason, // <- set your phone reason string
#"phoneType" : #[deviceOneDetail] // <- set your phone type dictionary within an array
};
// create phone list dictionary with any device dictionaries you want to add
NSDictionary *phoneListDict = #{
#"phoneList" : #[
deviceOne, // <- add your device to the phone list array of dictionaries
// deviceTwo...
]
};
NSString *jsonString = [self convertToJsonString:phoneListDict]; // <- convert the dictionary into a json string and use however you wish
// your json string should now look like this assuming you pass 'End of Contract', 5 & 'Android Smartphone' as arguments to this method
// {"phoneList":[{"phoneReason":"End of Contract","phoneType":[{"id":5,"phoneType":"Android Smartphone"}]}]}
}
-(NSString*) convertToJsonString:(NSDictionary*)dictionary
{
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary
options:0 // Pass 0 if you don't care about the readability of the generated string
error:&error];
if (error)
{
NSString *errorDesc = [NSString stringWithFormat:#"Error creating json data from dictionary: %#", error.localizedDescription];
NSLog(#"ERROR: %#", errorDesc);
jsonData = nil;
return nil;
}
NSString *returnString = nil;
if(jsonData != nil)
{
returnString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
return returnString;
}
I'm having trouble parsing the json output from a web service. I am using NSJSONSerialization to parse the output into an NSDictionary. Also using AFNetworking by subclassing AFHTTPSessionManager. For now the response serialiser is AFHTTPResponseSerializer which returns NSData
Here's the code I'm using:
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableLeaves error:&err];
Pretty straightforward. And the err object is nil so the conversion works fine.
BUT: the result I get straight from the web service is this:
"address":
{
"address1": "Ivy House",
"address2": "Sandy Lane",
"city": "Rush",
"postCode": null,
"email": "notknown#whatever.com",
"telephone": "18437584",
"mobile": null,
"smsAlert": null,
"county": "Dublin",
"country": "Ireland",
"websiteAddress": "www.example.com"
},
The result I get after printing the content of dict is this:
address = {
address1 = "Ivy House";
address2 = "Sandy Lane";
city = Rush;
country = Ireland;
county = Dublin;
email = "notknown#whatever.com";
mobile = "<null>";
postCode = "<null>";
smsAlert = "<null>";
telephone = 18437584;
websiteAddress = "www.example.com";
};
The issue is that the resulting NSDictionary does NOT have double quotes and so saving the NSDictionary to disk in plist format FAILS!
I have also tried using AFJSONResponseSerializer which returns NSDictionary but the contents are the same as above!
Where's the issue here?
Thanks in advance.
The problem here doesn't seem to be related to double quotes at all. When printed, NSDictionary (as well as other Foundation objects) drop enclosing double quotes when they are not needed (e.g. when no spaces or special characters in the string).
Now, the likely problem preventing you from serialising your NSDictionary to a property list is presence of nulls in the JSON and, consequently, in NSDictionary. According to documentation:
Property list objects include NSData, NSString, NSArray, NSDictionary, NSDate, and NSNumber objects.
Whereas nulls from JSON will be represented as instances of NSNull, thus making your NSDictionary an invalid Property List.
NSDictionary has different structure then JSON string. So when you parse a JSON string to NSDictionary you should not expect quotes.
You can save the JSON data and parse it again on runtime.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"yourfilename.dat"];
// Save it into file system
[data writeToFile:dataPath atomically:YES];
I have this JSON code:
[
{
"descrizione": "Risotto Giallo con Stinco",
"prezzo": null
},
{
"descrizione": "Orecchietta al ragu bolognese",
"prezzo": null
},
{
"descrizione": "Penne ai gamberi",
"prezzo": null
}
]
To print in a Text View, so that I wrote this code:
self.MenuGiorno.text = [self.MenuGiorno.text stringByAppendingString:[NSString stringWithFormat:#"%#",jsonArray1]];
Of course in this way I see in the Text View the complete code without parsing it.
How can I specify to print only "descrizione" and "prezzo"? Don't mind about Italian, this last two are the identifier I must use to fill the Text View. Someone has an idea?
The jasonArray1 is an array of dictionaries. First you must access the array element, there is only one, the dictionary. Then access the dictionary item by key name.
NSString *str = jsonArray1[0][#"descrizione"];
or more verbosely:
NSArray *fistArrayElement = [jsonArray1 firstObject];
NSString *str = [fistArrayElement objectAtIndex:#"descrizione"];
Is there any way to get JSON object from the server in the same order??
For example when i fitch using browser my JSON object return like this:
{
"23": {
"numberOfRecords": "3",
"startDate": "27/11/2013",
"endDate": "31/12/2014",
"question": "How do you rate the new MenaME Portal ?",
"voteScale": "5",
"questions": {
"option1": {
"value": "1",
"option": "Poor",
"voteResult": "50.000"
},
"option2": {
"value": "2",
"option": "Acceptable",
"voteResult": "0.000"
},
"option3": {
"value": "3",
"option": "Good",
"voteResult": "0.000"
},
"option4": {
"value": "4",
"option": "Very Good",
"voteResult": "0.000"
},
"option5": {
"value": "5",
"option": "Excellent",
"voteResult": "50.000"
}
},
"selectedAnswer": "0",
"voteAnswered": "0",
"votes": "6"
}
}
after parsing it with [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error]
the object returned like this :
{
23 = {
endDate = "31/12/2014";
numberOfRecords = 3;
question = "How do you rate the new MenaME Portal ?";
questions = {
option1 = {
option = Poor;
value = 1;
voteResult = "50.000";
};
option2 = {
option = Acceptable;
value = 2;
voteResult = "0.000";
};
option3 = {
option = Good;
value = 3;
voteResult = "0.000";
};
option4 = {
option = "Very Good";
value = 4;
voteResult = "0.000";
};
option5 = {
option = Excellent;
value = 5;
voteResult = "50.000";
};
};
selectedAnswer = 0;
startDate = "27/11/2013";
voteAnswered = 0;
voteScale = 5;
votes = 6;
};
}
Is there any way or framework to get the object as it (in the same order returned from the server) ??
Dictionaries, both in JSON and NSDictionary, are unordered, meaning that it is irrelevant which order you see things in the log. This is defined in the JSON specification and the documentation for NSDictionary.
If it actually matters what order things are displayed in, then either the API you are linking to isn't using correct JSON, or you're doing something wrong in your app. To help with those situations you can use several of the sorted NSDictionary implementations that are around.
Can I ask why you want to ensure the dictionary is maintained in the correct order?
I understand in some cases (mine) an ancient JSON -> XML web service was being called by my app and the client refused to adjust the service so it could accept unordered JSON (valid json) but if you're writing the app, why do you need to ensure that it is in order?
I have a NSMutableDictionary subclass that keeps objects added by setObject:forKey in the order you call the method that can be found here.
It works by storing a NSMutableOrderedSet of keys within the dictionary and then overrides the keyEnumerator method to return an enumerator based on the ordered set
- (NSEnumerator *)keyEnumerator
{
return [self.orderedSetOfKeys objectEnumerator];
}
You could modify the NSMutableDictionary subclass i created to expose the NSMutableOrderedSet in the public header and then modify this set yourself to get an ordered version of your dictionary.. For example:
NSDictionary *JSONWebServiceDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
LNOrderedMutableDictionary *orderedDictionary = [[LNOrderedMutableDictionary alloc] initWithDictionary:JSONWebServiceDictionary];
NSMutableOrderedSet *order = [[NSMutableOrderedSet alloc] initWithArray:#[#"key1",#"key2",#"key3"]]; //All the keys you are expecting and the order you want them in..
orderedDictionary.orderSet = order; //orderSet does not exist.. it is currently called `array` and not exposed in LNOrderedMutableDictionary.h
I haven't tested the code above but unless you want to create or modify an existing JSON parser then it seems that it is your only option..
If you did want to modify an existing parser then it might just be as simple as replacing dictionary instances with LNOrderedMutableDictionary to keep everything in order.
Another idea to expand the above sample code could be to replace
NSMutableOrderedSet *order = [[NSMutableOrderedSet alloc] initWithArray:#[#"key1",#"key2",#"key3"]];
with an array returned in the JSONWebServiceDictionary dictionary as arrays keep their order when parsed from JSON so maybe you could do this?
NSMutableOrderedSet *order = [[NSMutableOrderedSet alloc] initWithArray:[JSONWebServiceDictionary objectForKey:#"keyOrderArray"]]];
Look at what you have. If you test the result you got back from JSONObjectWithData (which we'll assume was declared as id jsonObject)
if ([jsonObject isKindOfClass:[NSDictionary class]) { ...
or
NSLog(#"The object type is %#", [jsonObject class]);
you will find that it is indeed an NSDictionary (or perhaps an NSMutableDictionary). That dictionary, as you can see from the dump (or infer from the nearly identical JSON) contains a single entry with a key of "23".
So let's cast the jsonObject to an NSDictionary and reference it:
NSDictionary* jsonDict = (NSDictionary*) jsonObject;
NSDictionary* entry23Dict = [jsonDict objectForKey:#"23"];
Now, if you NSLog entry23Dict you will discover it contains all of the above, absent the { 23 = ... } outermost dictionary.
You can then access, say, "questions" with
NSDictionary* questDict = [entry23Dict objectForKey:#"questions"];
From there the individual "option1", "option2", ... "option5" dictionaries can be accessed in a similar fashion. You simply proceed one layer at a time -- don't get overwhelmed by the entire structure. (It's often helpful, when you're first learning, to NSLog each "layer" as you "peel" it out of the containing structure.)
And, of course, you have all the standard facilities that are available to NSDictionary objects (and NSArray objects, should your JSON contain any [..] arrays). For instance, you can iterate on the keys of the dictionary with
for (NSString* key in jsonDict) {
NSLog(#"This entry's number is %#", key); // For the above will print "23"
NSDictionary* numberedDict = jsonDict[key]; // Using the "new" form of dictionary access
NSString* endDate = numberedDict[#"endDate"]; // Ditto
NSLog(#"The end date is %#", endDate);
}
This is a fairly common problem. It's also probably the most annoying part about iOS. (java doesn't have this issue at all). If you want to get back objects, take a look at restkit.org Specifically this answer may help: https://stackoverflow.com/a/8284343/836450
Update
It appears resultField is the one that has no value. Will look into this, but I'd still appreciate any advice.
Original Post
I've been set the task of coming up with a basic iOS application that simply makes a search request and then displays the results for university work. I tried to use the Google Custom Search engine but could never get it to work on the iPhone so I've had to resort to the depreciated Google Web Search API (The lecturer is okay with this).
Now, I'm able to make the request, and it returns the JSON data as intended, which I now must parse, I think. Sadly I only have a week to do this, which is crazy as I've never worked with JSON before.
What I'd like is if someone could help me get off the ground with a pointer or two in how to get even just a basic parsing of the JSON data.
I've looked around on Stackoverflow and saw some things that might be helpful like the breakdown structure in the selected answer here.
The person put this together, which when shown in the code makes some sense to me:
A great structure explanation
dictionary (top-level)
sethostname (array of dictionaries)
dictionary (array element)
msgs (string)
status (number)
statusmsg (string)
warns (array)
??? (array element)
Sadly I can't even begin to do the same with the code generated in my app. It takes the form similar to this example code, courtesy of google - I'm no Paris Hilton fan!
Example code from Google.
{"responseData": {
"results": [
{
"GsearchResultClass": "GwebSearch",
"unescapedUrl": "http://en.wikipedia.org/wiki/Paris_Hilton",
"url": "http://en.wikipedia.org/wiki/Paris_Hilton",
"visibleUrl": "en.wikipedia.org",
"cacheUrl": "http://www.google.com/search?q\u003dcache:TwrPfhd22hYJ:en.wikipedia.org",
"title": "\u003cb\u003eParis Hilton\u003c/b\u003e - Wikipedia, the free encyclopedia",
"titleNoFormatting": "Paris Hilton - Wikipedia, the free encyclopedia",
"content": "\[1\] In 2006, she released her debut album..."
},
{
"GsearchResultClass": "GwebSearch",
"unescapedUrl": "http://www.imdb.com/name/nm0385296/",
"url": "http://www.imdb.com/name/nm0385296/",
"visibleUrl": "www.imdb.com",
"cacheUrl": "http://www.google.com/search?q\u003dcache:1i34KkqnsooJ:www.imdb.com",
"title": "\u003cb\u003eParis Hilton\u003c/b\u003e",
"titleNoFormatting": "Paris Hilton",
"content": "Self: Zoolander. Socialite \u003cb\u003eParis Hilton\u003c/b\u003e..."
},
...
],
"cursor": {
"pages": [
{ "start": "0", "label": 1 },
{ "start": "4", "label": 2 },
{ "start": "8", "label": 3 },
{ "start": "12","label": 4 }
],
"estimatedResultCount": "59600000",
"currentPageIndex": 0,
"moreResultsUrl": "http://www.google.com/search?oe\u003dutf8\u0026ie\u003dutf8..."
}
}
, "responseDetails": null, "responseStatus": 200}
This is the code so far, which as you'll learn quickly does not really do much else than return code similar to the code above.
**My code.**
// query holds the search term
query = [query stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//append theQuery with search URL
NSString *tempString = [NSString stringWithFormat:#"%#/%#", #"https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=", theQuery];
//Create NSURL out of tempString
NSURL *url = [NSURL URLWithString:tempString];
// Create a request object using the URL.
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Prepare for the response back from the server
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONWritingPrettyPrinted error:&error];
NSDictionary* resultField = [NSDictionary dictionaryWithDictionary:[dictionary objectForKey:#"results"]];
// Send a synchronous request to the server (i.e. sit and wait for the response)
// Check if an error occurred
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
// Do something to handle/advise user.
}
// Convert the response data to a string.
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSArray *results = [dictionary objectForKey:#"results"];
//set label's text value to responseString's value.
endLabel.text = responseString;
Now the main issue I've encountered is that the results array is null all the time. I could really do with a point in the right direction here. Thank you.
It looks like you're having trouble traversing the data structure parsed out of the JSON.
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONWritingPrettyPrinted error:&error];
Assuming the data you passed in is good, this dictionary contains the top-level structure. It has three keys responseData, responseDetails, and responseStatus. (You could see this by NSLogging the dictionary.)
You're then querying that dictionary for the key results. It doesn't exist, so your resultField variable is set to nil. The dictionary's value for the key responseData is another dictionary which does contain a key results -- you need that middle step.
Also, the value for the results key in that second dictionary is an array (of more dictionaries), not a dictionary itself.
There is no need to create a new dictionary each time. For easier reading I'd recommend something like:
[[dictionary objectForKey:#"responseData"] objectForKey:#"results"]
There you have the array of results. You can then add
[ [dictionary objec...] objectAtIndex:0]