When I parse the data of google API for local police station details, it returns an NSDictionary in it with a complex form:
result = (
{
geometry = {
location = {
lat = "22.72187";
lng = "75.8741";
};
};
icon = "http://maps.gstatic.com/mapfiles/place_api/icons/police-71.png";
id = 5bf224eb03bee960670c048f7dcdb2684d6aed1f;
name = "Name Police Station";
reference = "CoQBgAAAACG6clYx-1ycnenczJfECFggwSCVzxqFR8GKwMYpA1QbP1VTRIgHHYNXW7z0kOw9IRuV9gKJ-ES19tf46CcwUShwT_lznIX36sx_F8aKFjYE3APa0zNWRxSGY0fDQ95HwinR9HXhTWeL0ncPHSLo9cL9FB8OlBJF-tYNRP5ZThuMEhCQH0lSxrelWOd";
type = (
police,
establishment
);
vicinity = "Yeshwant Niwas Road, Sanghi Colony";
},
Here, I got many objects of geometry, id, name.
How do I use this data in a simple NSArray and NSDictionary?
NSDictionary *dict = [NSArray>Object objectatIndex:index];
then dict would return value for key like it would return [[dict objectforkey:#"name"];.
Apple documentation helped me to solve above problem:
I use this code to solve above dictionary problem-
NSArray *arryDict = [dictPoliceStatin objectForKey:#"result"];
NSEnumerator *enumerator = [arryDict objectEnumerator];
NSDictionary *anObject;
while (anObject = [enumerator nextObject]) {
/* code to act on each element as it is returned */
NSMutableDictionary *diceGloable = [[NSMutableDictionary alloc] init];
[diceGloable setObject:[[[anObject objectForKey:#"geometry"]objectForKey:#"location"] objectForKey:#"lat"] forKey:#"lat"];
[diceGloable setObject:[[[anObject objectForKey:#"geometry"]objectForKey:#"location"] objectForKey:#"lng"] forKey:#"lng"];
[diceGloable setObject:[anObject objectForKey:#"name"] forKey:#"name"];
[diceGloable setObject:[anObject objectForKey:#"vicinity"] forKey:#"vicinity"];
[arrayMapValues addObject:diceGloable];
}
ObjectEnumerator helped here, arrayMapsValues is the NSMutablearray class object.
Take a look at the FTGooglePlacesAPI library I'm currently working on. This is a complete library for interaction with the Google Places API using simple, block-based Objective-C interface.
There is no readme or how-to at the moment as I don't consider it final/released yet. But it works pretty fine and there is a very detailed, well-commented example project.
You can find the library here: https://github.com/FuerteInternational/FTGooglePlacesAPI
Or you can utilize valueForKeyPath: method of some collections from NSFoundation, which is often overlooked, but very powerful.
Example:
NSDictionary *firstItem = results[0];
NSNumber *lat = [firstItem valueForKeyPath:#"geometry.location.lat"];
Related
I'm having a hard time managing to pull anything out of a JSON response when querying TMDb. Despite spending most of the weekend searching these forums and others, I am no nearer a solution.
In my header file I have:
#property (nonatomic,strong) NSDictionary * fetchedData;
The dictionary is populating correctly, since the first part of the JSON response looks like this when I use:
NSLog(#"fetchedData: %#", fetchedData);
fetchedData: {
page = 1;
results = (
{
adult = 0;
id = 1245;
"known_for" = (
{
adult = 0;
"backdroppath" = "/hbn46fQaRmlpBuUrEiFqv0GDL6Y.jpg";
"genreids" = ( 878, 28, 12 );
id = 24428;
"mediatype" = movie;
"original_language" = en;
"original_title" = "The Avengers";
I've been trying numerous ways to retrieve all instances of "original_title" (or any of the keys) in the response, but I have no hair left to pull out when every attempt is returning NULL, so any suggestions are welcome!
Try this.
NSString *title = fetchedData[#"results"][0][#"known_for"][0][#"original_title"];
Getting data from Response
I think fetchedData is dictionary.So
NSString *strOriginalTitle = [NSString stringWithFormat:#"%#",[[[[[fetchedData valueForKey:#"results"]objectAtIndex:0]valueForKey:#"known_for"]objectAtIndex:0]valueForKey:#"original_title"];
//OR By getting data step by step
NSArray *arrayResults = [fetchedData valueForKey:#"results"];
NSDictionary *dict = [[arrayResults objectAtIndex:0] copy];
NSArray *arrayKnownFor = [dict valueForKey#"known_for"] copy];
NSString *strOriginalTitle = [arrayKnownFor objectAtIndex:0]valueForKey:#"original_title"];
NSLog(#"The original_title is - %#",strOriginalTitle);
I am getting String data from server in the format below. I want to get the value for every tag like phonenumber and name etc. I am able to convert it in array by comma separator. how to get individual values?
Company:Affiliated CO,Organization:TECHNICAL EDUCATION
SOCIETY,Organization:SINHGAD,Organization:National Basketball Association,Person:Parikshit N. Mahalle,PhoneNumber:81 98 22 416 316,PhoneNumber:9120-24100154,Position:Professor,SportsEvent:NBA.
Say your original string is stored in rawString.
You need to :
1) split the string by ,
NSArray *pieces = [rawString componentsSeparatedByString:#","];
2) for each item in this array, split it by :, and add it to a dictionary :
NSMutableDictionary *dict = [NSMutableDictionary new];
for (NSString *piece in pieces) {
NSArray *splitPiece = [piece componentsSeparatedByString:#":"];
// key is at splitPiece[0], value is at splitPiece[1]
dict[splitPiece[0]] = splitPiece[1];
}
Then you'll have a dictionary of what you wanted in the first place.
But as suggested in the comments, it would be far better (and more flexible) for you to receive JSON data.
Edit: your original string shows there are multiple fields named Organization. The code I've given is not designed to handle such cases, it's up to you to build upon it.
If this data is not being returned as a JSON object then you'll have to go with #Clyrille answer. But if it is JSON then NSJSONSerialization:JSONObjectWithData:options:error: will be the way to go.
EXAMPLE
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:/*urlResponse*/ options:0 error:nil];
NSString *company = [json objectForKey:#"Company"];
NSString *Organization = [json objectForKey:#"Organization"];
NSString *Person = [json objectForKey:#"Person"];
NSString *PhoneNumber = [json objectForKey:#"PhoneNumber"];
NSString *Position = [json objectForKey:#"Position"];
NSString *SportsEvent = [json objectForKey:#"SportsEvent"];
- (void)retrieveData
{
NSURL * url = [NSURL URLWithString:#"***/connection.php"];
NSData * data = [NSData dataWithContentsOfURL:url];
_json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
_questionsArray = [[NSMutableArray alloc]init];
for (int i = 0; i < _json.count; i++)
{
NSString * qID = [[_json objectAtIndex:i] objectForKey:#"id"];
NSString * qTitle = [[_json objectAtIndex:i] objectForKey:#"question_title"];
NSString * qA = [[_json objectAtIndex:i] objectForKey:#"A"];
NSString * qB = [[_json objectAtIndex:i] objectForKey:#"B"];
NSString * qC = [[_json objectAtIndex:i] objectForKey:#"C"];
NSString * qD = [[_json objectAtIndex:i] objectForKey:#"D"];
NSString * qAnswer = [[_json objectAtIndex:i] objectForKey:#"question_answer"];
question * myQuestion = [[question alloc] initWithQuestionID:qID andQuestionName:qTitle andQuestionA:qA andQuestionB:qB andQuestionC:qC andQuestionD:qD andQuestionAnswer:qAnswer];
[_questionsArray addObject:myQuestion];
}
[_json enumerateObjectsUsingBlock:^(NSDictionary *questionDictionary, NSUInteger idx, BOOL *stop) {
//Here I'm treating the index like an NSNumber, if your code is expecting a string instead use
//#(idx).stringValue
[_questions setObject:questionDictionary forKey:#(idx)];
//or the modern equivalent
//questions[#(idx)] = questionDictionary;
//If you want to use your 'questions class' then create one and put it into the array instead of the dictionary pulled from the array.
}];
NSLog( #"%#", _questions );
}
Logs (null)
random gobledy gook so my post isn't mostly code
random gobledy gook so my post isn't mostly code
random gobledy gook so my post isn't mostly code
random gobledy gook so my post isn't mostly code
random gobledy gook so my post isn't mostly code
If I understand your question correctly it becomes something like this
self.questions = .... //I assume this is the array you reference 'question' objects that is created by your retrieve data method
//this used to be created by pulling an object out of your questions dictionary with the key i interpreted as a string.
//now that it's an array you should be able to just reference it by index, assuming they were inserted in order
//I'm also assuming that what comes out of the aray is a question object given the code you provided with the signature
//- (id) initWithQuestionID: (NSString *) qID andQuestionName: (NSString *) qName andQuestionA: (NSString *) qA andQuestionB: (NSString *) qB andQuestionC: (NSString *) qC andQuestionD: (NSString *) qD andQuestionAnswer: (NSString *) qAnswer
Question *nextQuestion = self.questions[i];
self.answer = nextQuestion.questionAnswer;
self.questionLabel.text = nextQuestion.questionLabel;
//and so on
I also suggest the following edit to replace your for loop. It uses a for in loop instead, this saves you from having to keep track of an index and looks cleaner. It also helps so you don't keep repeating the [_json objectAtIndex:i] chunk of code. I also use modern objective-c syntax to access the dictionary.
for (NSDictionary *questionDictionary in _json)
{
NSString * qID = questionDictionary[#"id"];
NSString * qTitle = questionDictionary[#"question_title"];
...
question * myQuestion = [[question alloc] initWithQuestionID:qID andQuestionName:qTitle andQuestionA:qA andQuestionB:qB andQuestionC:qC andQuestionD:qD andQuestionAnswer:qAnswer];
[_questionsArray addObject:myQuestion];
}
If you need the key along with the object in the dictionary then you can clean it up in a similar way with the enumerateObjectsUsingBlock
[_json enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
//your code here
}];
EDIT
It sounds like what your really wanting to do is to pull down your JSON but keep all your other code the way it was when you were using a dictionary that you got from your plist. So in this case you want your parsing function to return a dictionary instead of an array. If that's the case it's worth sidestepping into computer science for a second.
NSDictionarys are also known as a hash, map, symbol table, or associative array. Some languages (such as Lua) don't have an array collection like NSArray, they only have dictionaries. From a dictionary you can create many of the other collections your used to like arrays (and sets too). Heres how it works: Instead of an ordered collection of elements with an index, you place the items in a dictionary and use what would have been the index as the key, and the value becomes, well, the value. For example an array and it's equivalent associative array (aka dictionary):
NSArray *array = #[#"hello", #"world", #"!"];
NSDictionary *dictionary = #{#(1): #"hello",
#(2): #"world",
#(3): #"!"};
This is exactly what your doing when you load in the data from your plist because the first elements key is 0 followed by another dictionary, and I'm supposing that the next element in the list is 1 followed by another dictionary. Inside your parsing function it becomes
NSMutableDictionary *questions = [[NSMutableDictionary alloc] init];
[_json enumerateObjectsUsingBlock:^(NSDictionary *questionDictionary, NSUInteger idx, BOOL *stop) {
//Here I'm treating the index like an NSNumber, if your code is expecting a string instead use
//#(idx).stringValue
[questions setObject:questionDictionary forKey:#(idx)];
//or the modern equivalent
//questions[#(idx)] = questionDictionary;
//If you want to use your 'questions class' then create one and put it into the array instead of the dictionary pulled from the array.
}];
This of course assumes that your api is going to return the JSON questions in the order you want.
I have an iOS app that is using RestKit and CoreData. I have run into a road block with making a POST request because the request body is formed from a NSDictionary. The problem I have is the request body needs to have duplicate keys. NSDictionary requires unique keys so I'm not sure how to make this work.
Here is how the server is expecting the request body.
<node>
<personId>2</personId>
<status>2</status>
<title>Dinosaur unearthed somewhere out there. </title>
<point>
<city>Somewhere</city>
<copy><![CDATA[An amazing discovery was unearthed as a local farmer was plowing his field]]></copy>
<state>Outthere</state>
<sequence>1</sequence>
</point>
<point>
<city>Somwhere</city>
<copy><![CDATA[Archeologists from around the world are amazed at the pristine condition of the remains. Also of note is that the farmer was only using a single blade plow on his John Deere tractor when it was unearthed. ]]></copy>
<sequence>2</sequence>
<state>Outthere</state>
</point>
<point>
......
</point>
</node>
This is a simplified version of how I tried to make it work....
params = [[NSMutableDictionary alloc] init];
nodes = [[NSMutableDictionary alloc] init];
nodeParams = [[NSMutableDictionary alloc] init];
NSString *personId = #"2";
NSString *status = #"2";
NSString *title = #"Dinosaur unearthed somewhere out there.";
NSString *city = #"Somewhere";
NSString *state = #"OutThere";
NSString *copyField = #"Testing this out to see if it works";
//Here I set up the point layer of the request body
//In my code this three line section is in a loop. Obviously this does not work because it just overwrites the objectForKey each time through the loop.
[params setObject:copyField forKey:#"copy"];
[params setObject:city forKey:#"city"];
[params setObject:state forKey:#"state"];
//Here I Set up the Node Layer of the request body
[nodeParams setObject:params forKey:#"point"];
[nodeParams setObject:personId forKey:#"personId"];
[nodeParams setObject:status forKey:#"status"];
[nodeParams setObject:title forKey:#"title"];
[nodes setObject:nodeParams forKey:#"node"];
NSLog(#"The Dictionary is %#",nodes);
At runtime the log shows that the body is formatted properly except their is only one point layer and it is populated with the data from the final pass in the loop. Does anyone know of any trickery to get around this?
As a note I believe the postObject method requires the NSDictionary because it passes the dictionary to a JSON Serialization tool. I suspect the serialization tool is expecting a dictionary to be passed in. If someone knows otherwise correct me if I'm wrong.
Okay I finally figured this out. It wasn't until I converted the XML above into JSON that I realized how it could be done. The key is recognizing how an Array and NSDictionary are formatted in the 'NSJSONSerialization' class.
Here is an example of how the server was expecting the JSON.
{ "status":"2",
"title":"test #5",
"personId":"1",
"point":[
{ "copy":"<p class=\"pt\" data-seq=\"1\">This is paragraph #1<\/p>",
"state":"OutThere",
"city":"Somewhere",
"sequence":"1"
},
{ "copy":"<p class=\"pt\" data-seq=\"2\">This is paragraph #2<\/p>",
"state":"OutThere",
"city":"Somewhere",
"sequence":"2"
}
]
}
The critical thing to note here is that the "point" field is and Array of Dictionaries. The [ denotes an array. Once I finally clued in on that I realized that each time through the loop I could reinitialize my dictionary, add the new objects, and then add the current dictionary to the array as you can see below.
while (![theScanner isAtEnd]) {
count = count +1;
//Initialize the dictionary
points = [[NSMutableDictionary alloc] init];
NSString *htmlTag = [NSString stringWithFormat:#"<p class=\"pt\" data-seq=\"%d\">",count];
[theScanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:&temp];
NSString *preTagText = [htmlTag stringByAppendingString:temp];
NSString *postTagText = [preTagText stringByAppendingString:#"</p>"];
NSString *sequence = [NSString stringWithFormat:#"%d",count];
[points setObject:postTagText forKey:#"copy"];
[points setObject:sequence forKey:#"sequence"];
[points setObject:city forKey:#"city"];
[points setObject:state forKey:#"state"];
[pointArray addObject:points];
points = nil;
}
[params setObject:titleText forKey:#"title"];
[params setObject:personIdNumber forKey:#"personId"];
[params setObject:status forKey:#"status"];
[params setObject:pointArray forKey:#"point"];
After the loop is finished I just add the pointArray to the dictionary as the object with the key point (Thanks Wain). I add the title, status, and personId objects to the same dictionary and use it as the NSDictionary required for the Restkit POST request.
May I know is that possible for NSDictionary or NSMutableDictionary to add in multiple same keys for different object? It is because of the API that written by the developers are accepting an array.
e.g:
NSArray *ids = #[#"xxx", #"yyy", #"zzz"];
NSMutableDictionary *args = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"someobject", #"somekey"];
I've defined an args and set of ids that picked by user and now I will loop the array.
for( NSString *getId in ids ){
[args setObject:getId forKey:#"ids[]"];
}
So ended up, the results come out are
"somekey" = "someobject", "ids[]" = "zzz";
Is that possible for me to get result as follows?
"somekey" = "someobject", "ids[]" = "xxx", "ids[]" = "yyy", "ids[]" = "zzz";
Please advise, thanks!
Yes it is possible
NSArray *arr = [[NSArray alloc]initWithObjects:#"xxx",#"yyy",#"zzz", nil];
NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"Someobject", #"Somekey", nil];
for (int i = 0; i<[arr count]; i++) {
[dic setValue:[arr objectAtIndex:i] forKey:[NSString stringWithFormat:#"id[%d]", i]];
}
NSLog(#"dic %#",dic);
Use this code sure it would help you.
No, key is unique. But you can put an NSMutableArray in your NSDictionary, and store you values like key => array(x,y,...)
Instead of that you can create Dictionary like this.
YourDictionary = {
"somekey" = "someobject",
"ids[]" = (
"xxx",
"yyy",
"zzz"
)
}
Treat ids[] as an array
Hope this will solve your problem
No that's not the way a dictionary should be used. As peko said, just put your array in the dict:
[args setObject:ids forKey:#"ids"];