Extract from NSDictionary object - objective-c

I used json-framework to pull a JSON string from and URL and convert the JSON string to NSDictionary object with these two lines of code
SBJsonParser* parser = [SBJsonParser new];
NSDictionary* myDict = [parser objectWithString:resp];
My NSDicitonary has:
(
{
condition = no;
date = "2013-06-21";
"location_id" = 9;
name = Chabahil;
reason = "";
time = "03:04:22";
},
{
condition = pressure;
date = "2013-06-21";
"location_id" = 7;
name = Maitighar;
reason = "Peak Hour";
time = "03:04:13";
}
)
Now I need to access each element for example I want to get value of "name" of the second element. I couldnot figure out how to do it.
Thanks!

The JSON string contains not a dictionary, but an array (of two dictionaries).
So you would do
SBJsonParser* parser = [SBJsonParser new];
NSArray* jsonArray = [parser objectWithString:resp];
and access the values for example like
NSString *secondName = [[jsonArray objectAtIndex:1] objectForKey:#"name"];
or, using the modern subscripting syntax:
NSString *secondName = jsonArray[1][#"name"];
(Note that there already is a NSJSONSerialization class in Foundation, so unless you
have a specific reason to use SBJsonParser, you could use that as well.)

Related

Get Property within an Object within a Dictionary - Objective C

I need to access a property within a dictionary and I am having a difficult time doing so.
Dictionary:
{
Id = "123";
Animal = {
Id = "456";
Type = "Dog";
Sound = "Bark";
}
}
Code:
NSString *animalType = dictionary[#"Animal.Type"];
All I get back is (null). What would be the proper way to call this in order to get "Dog"?
Try
NSString *animalType = dictionary[#"Animal"][#"Type"];
Or
NSString *animalType = [[dictionary objectForKey:#"Animal"] objectForKey:#"Type"];

I don't understand how to use the JSON data in Xcode

I have successfully downloaded and parsed (I think) the JSON data
NSURL *quoteURL = [NSURL URLWithString:#"http://www.qwoatzz.com"];
NSData *jsonData = [NSData dataWithContentsOfURL:quoteURL];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
However, I'm not too sure how to actually use the JSON data. If the JSON file has an array with two keys, how do I get a value from one of these keys at a specific index (the first one for example) and use that to change the text of a label (I know how to do that, it's just the JSON part I am stuck on)?
2014-10-20 19:46:10.616 Qwoatz-2[3147:454481] dataDictionary : {
count = 10;
"count_total" = 1871;
pages = 188;
posts = (
{
author = "Jason Seifer";
date = "2014-10-20 13:54:11";
id = 24317;
thumbnail = "http://blog.teamtreehouse.com/wp-content/uploads/2014/10/1634685862_92b26b9167_o-150x150.jpg";
title = "What Employers Are Looking For in a Junior Rails Developer";
url = "http://blog.teamtreehouse.com/employers-looking-junior-rails-developer";
},
{
author = "Zac Gordon";
date = "2014-10-16 09:27:38";
id = 24296;
thumbnail = "http://blog.teamtreehouse.com/wp-content/uploads/2014/10/brochure-site-150x150.png";
title = "When is WordPress.com the Right Solution?";
url = "http://blog.teamtreehouse.com/wordpress-com-right-solution-website";
},
{
author = "Gill Carson";
date = "2014-10-15 12:52:43";
id = 24287;
thumbnail = "http://blog.teamtreehouse.com/wp-content/uploads/2014/10/Tahoe_team-Photo-150x150.jpg";
title = "We Are Family – The Whole Team!";
url = "http://blog.teamtreehouse.com/family";
},
{
author = "Jason Seifer";
date = "2014-10-14 15:26:11";
id = 24292;
thumbnail = "http://blog.teamtreehouse.com/wp-content/uploads/2014/10/Chartist-Simple-responsive-charts-2014-10-14-15-24-43-150x150.jpg";
title = "Responsive Charts";
url = "http://blog.teamtreehouse.com/responsive-charts";
},
{
author = "Guil Hernandez";
date = "2014-10-13 09:28:05";
id = 24228;
thumbnail = "http://blog.teamtreehouse.com/wp-content/uploads/2014/09/blend-mode-mult-150x150.jpg";
title = "Cutting-Edge CSS Features You Can Use Today";
url = "http://blog.teamtreehouse.com/cutting-edge-css-features-can-use-today";
},
{
author = "Faye Bridge";
date = "2014-10-10 09:00:45";
id = 24230;
thumbnail = "http://blog.teamtreehouse.com/wp-content/uploads/2014/09/Nick-Bryan-150x150.jpg";
title = "After Just 6 Months Learning Nick is a full-time Web Developer";
url = "http://blog.teamtreehouse.com/6-months-nick-now-full-time-web-developer-major-computing-firm";
},
{
author = "Pasan Premaratne";
date = "2014-10-09 13:59:23";
id = 24250;
thumbnail = "http://blog.teamtreehouse.com/wp-content/uploads/2014/10/Screen-Shot-2014-10-06-at-5.57.16-PM-150x150.png";
title = "Making a Network Request in Swift";
url = "http://blog.teamtreehouse.com/making-network-request-swift";
},
{
author = "Zac Gordon";
date = "2014-10-09 09:21:29";
id = 24278;
thumbnail = "http://blog.teamtreehouse.com/wp-content/uploads/2014/10/wordpress_themes-150x150.jpg";
title = "New Course: WordPress Theme Development";
url = "http://blog.teamtreehouse.com/new-course-wordpress-theme-development";
},
{
author = "Dave McFarland";
date = "2014-10-08 13:47:55";
id = 24255;
thumbnail = "http://blog.teamtreehouse.com/wp-content/uploads/2014/10/Screen-Shot-2014-10-06-at-1.02.40-PM-150x150.png";
title = "How to Install Node.js and NPM on a Mac";
url = "http://blog.teamtreehouse.com/install-node-js-npm-mac";
},
{
author = "Jason Seifer";
date = "2014-10-07 16:15:00";
id = 24273;
thumbnail = "http://blog.teamtreehouse.com/wp-content/uploads/2014/10/html5-device-mockups-150x150.jpg";
title = "Device Mockups";
url = "http://blog.teamtreehouse.com/device-mockups";
}
);
status = ok;
}
An example JSON file that was parsed.
Loop through the dictionary:
for(NSString *key in dataDictionary) {
id myObject = [dataDictionary objectForKey:key];
//do something with myObject
}
An NSDictionary is not an ordered collection, so there is no guarantee that looping through a dictionary as shown above will always loop through the keys in the same order. Apple doesn't provide an ordered dictionary with Cocoa/Cocoa Touch, and generally it is a bad idea to subclass NSDictionary or NSMutableDictionary as they are part of a class cluster.
Looking at the text from your example, posts is actually an array full of dictionaries. Assuming all the keys in your example are constant across the JSON files that you will be fetching, you could retrieve it using
NSArray *posts = [dataDictionary arrayForKey:#"posts"];
This array already appears to be ordered by date. You could then get the title for each post
for(int i = 0; i < [posts count]; i++) {
NSString *title = [((NSDictionary *)(posts[i])) objectForKey:#"title"];
//do something with title
}
1) Do you know the data is an array?
the JSON file has an array with two keys,...
value from one of these keys at a specific index...
This is somewhat of a mixed metaphor for me. When I have a JSON Array or NSArray, I tend to only think of indices (since that how arrays are ordered), and when I have JSON Objects or NSDictionaries, I tend to think of keys.
So, does the return value look like this:
[ "cat", 1, "a" ]
or does the data look like this:
{
"cat": {
"count": 1,
"tag": "a"
}
}
The first example is an Array with 3 elements; the second is an Object with 1 member that itself has 2 members.
2) If the data is correctly parsed as either an NSArray, or NSDictionary ...
Then you simply need to extract the data you want, with the accessors available on either container.
E.g.
NSArray *a = ...
[a firstObject];
[a objectAtIndex:0]; // same as above
NSDictionary *d = ...
d[#"memberName"];
[d objectForKey:#"memberName"]; // same as above
You'll want to actually save that data, or pass it to be processed, instead of just invoking the accessor.
UPDATE: based on the example data updated in the question.
One method is that you could extract the data both a bit manually, and iteratively.
NSDictionary *dataDictionary = ...
NSInteger count = [[dataDictionary objectForKey:#"count"] integerValue];
NSInteger countTotal = [[dataDictionary objectForKey:#"count_total"] integerValue];
NSInteger pagesCount = [[dataDictionary objectForKey:#"pages"] integerValue];
NSString *status = [dataDictionary objectForKey:#"status"];
NSArray *posts = [dataDictionary objectForKey:#"posts"];
for (NSDictionary *post in posts) {
for (NSString *key in post) {
NSLog(#"%#: %#", key, post[key]);
}
}
When you log dataDictionary, unquoted elements that are clearly strings are strings, elements in quotes are strings, integers and other numbers are likely usable numbers, but they may be strings (depends on return format), the date will be a string (and you can use NSDate and NSDateFormatter to pretty print it), status is just a string; for posts, the '(' and ')' wrap an array, and '{','}' wrap dictionaries.
UPDATE 2:
If you really want to do advanced searching, you can use NSPredicate to filter NSDictionary's or NSArray's. For example, something like the following would work:
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
NSDictionary *data = #{
#"stuff": #1,
#"posts": #[
#{ #"id": #1, #"title": #"one" },
#{ #"id": #2, #"title": #"two" },
#{ #"id": #3, #"title": #"three" },
#{ #"id": #4, #"title": #"four" },
#{ #"id": #5, #"title": #"five" },
]
};
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.id == %#", #4];
NSString *title = [[data[#"posts"] filteredArrayUsingPredicate:predicate] firstObject];
NSLog(#"title: %#", title);
}
}
prints
title: {
id = 4;
title = four;
}
You can use JSONModel Framework
JSONModel is a data model framework for iOS and OSX. It's written in Objective-C and helps you in several different ways.
You can read more about its key features below:
Rapidly write model code
Validation of the model's input
Atomic data
Type casting between JSON and Obj-C
Built-in data transformers
Custom data transformers
Model cascading
Convert back & forth from/to JSON
Persist model state in memory or file
Create models straight from the Internet
Automatic model compare methods
Note Please make sure your properties name match with key name in JSON
JSONModel Framework
GitHub Link

How to remove elements of NSDictionary

I have NSArray of NSDictionaries I need to extract 2 values or remove the values I don't need from the dictionary in the example below I need to remove id and NumberValue. any of you knows how can I do that?
Array: (
{
customerUS= {
DisplayName = "level";
InternalName = "Number 2";
NumberValue = 1;
id = xwrf
},
customerCAN= {
DisplayName = "PurchaseAmount";
InternalName = "Number 1";
NumberValue = 3500;
id = adf;
};
}
)
I'll really appreciate your help.
First thing, You can not remove/insert/update value in (immutable) NSDictionary/NSArray you need to convert NSDictionary/NSArray to (mutable) NSMutableDictionary/NSMutableArray.
such like
NSArray *myArr = ....;
NSMutableArray *newMutableArr = [myArr mutableCopy];
Then you can change in newMutableArr.
Such like
for(int i = 0 ; i < newMutableArr.count ; i ++)
{
[[newMutableArr objectAtIndex:i] removeObjectForKey:#"id"];
[[newMutableArr objectAtIndex:i] removeObjectForKey:#"NumberValue"];
}
EDITED:
Without Use of for loop and removeObjectForKey, if you have array of dictionary and both are mutable then you can also delete a key and its object from all elements of the array like this:
[newMutableArr makeObjectsPerformSelector:#selector(removeObjectForKey:) withObject:#"id"];
[newMutableArr makeObjectsPerformSelector:#selector(removeObjectForKey:) withObject:#"NumberValue"];
I would advice you to read Apple documents.
For modifying any Collection object after it is created, you need the mutable version.
For NSDictionary we have NSMutableDictionary. Read here.
We have a method for removing objects:
- (void)removeObjectForKey:(id)aKey
There are other methods as well. You can easily refer them in the above mentioned documentation.
Find out removeObjectForKey for deleting record from NSMutabledictionary.
removeObjectForKey pass the key value whatever you have like
all this are your key
DisplayName,
InternalName,
NumberValue,
id
do like this
removeObjectForKey:#"id";
First of all you have to convert the array to mutable array and then you can remove the key-value pairs from dictionary.
NSMutableArray *mutableArray = [yourArray mutableCopy];for(int i=0;i<mutableArray.count;i++){ NSMutableDictionary *outerDictionary = [mutableArray objectAtIndex:i]; for(NSString *key in outerDictionary.allKeys){ NSMutableDictionary *innerDictionary = [outerDictionary objectForKey:key]; [innerDictionary removeObjectForKey:#"id"]; [innerDictionary removeObjectForKey:#"NumberValue"]; }
}

Why does changing a mutable array contained in a dictionary not require updating the dictionary?

I was trying a piece of code from CS193P course (Objective-C). I noticed something in the way that the compiler works. An NSMutableArray called photos was added to an NSMutableDictionary, photosByPhotographer. Later on, a change was made to photos without any changes to photosByPhotographer. When I logged photosByPhotographer, the change was automatically applied to it and it did not need any extra lines of code!
I wonder how the compiler makes this work? Any materials to read from?
The code is as follows:
- (void)updatePhotosByPhotographer
{
NSMutableDictionary *photosByPhotographer = [NSMutableDictionary dictionary];
for (NSDictionary *photo in self.photos) {
NSString *photographer = [photo objectForKey:FLICKR_PHOTO_OWNER];
NSMutableArray *photos = [photosByPhotographer objectForKey:photographer];
if (!photos) {
photos = [NSMutableArray array];
[photosByPhotographer setObject:photos forKey:photographer];
NSLog(#"photosByPhotographer in if: %#", photosByPhotographer);
}
[photos addObject:photo];
NSLog(#"photosByPhotographer after if: %#", photosByPhotographer);
}
self.photosByPhotographer = photosByPhotographer;
}
The NSLog() result is as follows:
2012-07-20 20:05:57.618 Shutterbug[453:f803] photosByPhotographer in if: {
Dowbiggin = (
);
}
2012-07-20 20:05:57.620 Shutterbug[453:f803] photosByPhotographer after if: {
Dowbiggin = (
{
accuracy = 16;
context = 0;
dateupload = 1342836026;
description = {
"_content" = "";
};
farm = 9;
"geo_is_contact" = 0;
"geo_is_family" = 0;
"geo_is_friend" = 0;
"geo_is_public" = 1;
id = 7612787270;
isfamily = 0;
isfriend = 0;
ispublic = 1;
latitude = "37.307085";
longitude = "-121.900395";
originalformat = jpg;
originalsecret = 052e70d412;
owner = "22751315#N05";
ownername = Dowbiggin;
"place_id" = cils8sJUV7MeXHwt9A;
secret = 4437007c99;
server = 8161;
tags = "square squareformat iphoneography instagramapp uploaded:by=instagram foursquare:venue=49f13597f964a5209c691fe3";
title = "My little goofball";
woeid = 55971033;
}
);
}
That's because in Cocoa, you are using objects and pass by reference.
Imagine this code:
NSMutableArray *a, *b;
a = [NSMutableArray new];
[a addObject:#"A"]; // a contains #"A"
b = a; // b is assigned to the same object
[b addObject:#"B"]; // a and b contain #"A", #"B"
NSLog(#"a = %p and b = %p", a, b); // same values
The variables a and b point to the same object. You can also see that by comparing the pointer values.
However, if we do the following:
NSMutableArray *a, *b;
a = [NSMutableArray new];
[a addObject:#"A"]; // a contains #"A"
b = [[a mutableCopy] autorelease]; // b is assigned to a COPY of the object
[b addObject:#"B"]; // b contains #"A", #"B", while a still contains #"A"
NSLog(#"a = %p and b = %p", a, b); // NOT the same values
b is assigned to a copy of a (not the original), so b points to an other object. You can check by comparing the addresses of the objects.
The photos arrays is stored by reference in the NSDictionary, not as a copy. Therefore, if you change the underlying array, you will see that when you access the dictionary.
This is why it can be dangerous to provide some mutable types by reference instead of storing copies of them.
You need to understand how pointers and references work. Basically rather than variables in your code being actual full structures and objects, generally they are references or pointers to those structures. You can visualise the concept in a number of ways, but perhaps one that's useful is to think of a variable such as:
NSDictionary *myDict;
being really just a number which is the memory address of the myDict object. Here's a visualisation of how it works:
Your NSDictionary reference points to an object in memory which itself holds multiple references to other objects, which can be changed without affecting the dictionary itself. In this example I've shown an NSArray having a new object added to it. The reference to the array from the dictionary remains the same. There is only ever one instance of the array and the objects in it at any time.
When you call NSLog on an NSDictionary object then its method description is called.
In the implementation of the method description, NSDictionary is calling the description method of each value (object) of all its keys.
So when a value (object) changes so does the output of its description method change.
That is why it is reflected when calling NSLog on an NSDictionary object again.

How to enumerate all named captures in RegexKit?

I recently wanted use regex in Cocoa app. But I found that Cocoa does not include a regex class. So I decided to use RegexKit (OgreKit is good, but I don't know why it did not run fine on my OSX 10.6.4 x86_64).
I have a file content like:
12:20:30 - 01:20:30
some text
11:20:30 - 04:20:30
some text
And I want to pick up all time values and text values.I found this example code in a guide:
NSString *entireMatchString = NULL, *totalString = NULL, *dollarsString = NULL, *centsString = NULL;
NSString *regexString = #"owe:\\s*\\$?(?<total>(?<dollars>\\d+)\\.(?<cents>\\d+))";
[#"You owe: 1234.56 (tip not included)" getCapturesWithRegexAndReferences:regexString,#"$0", &entireString,#"${total}", &totalString,#"${dollars}", &dollarsString,#"${cents}",&centsString,nil];
// entireString = #"owe: 1234.56";
// totalString = #"1234.56";
// dollarsString = #"1234";
// centsString = #"56";
So I wrote a regex string
NSString *regexString = #"\\s*\\n*(?<start>\\d\\d:\\d\\d:\\d\\d*)\\s*-\\s*(?<end>\\d\\d:\\d\\d:\\d\\d*)\\s*\\n*(?<text>.*)
and it worked fine, but it only works once. I need to pick up all named captures, like we do in Ogrekit, e.g.:
OGRegularExpression *regex = [OGRegularExpression regularExpressionWithString:#"<video src=\"(?<imageURL>.+)\".+>"
options:OgreCaptureGroupOption
syntax:OgreRubySyntax
escapeCharacter:OgreBackslashCharacter];
NSArray *matches = [regex allMatchesInString:#"<video src=\"http://test.com/hello.jpg\">"];
if (matches != nil && ([matches count] == 1))
{
OGRegularExpressionMatch *match = [matches objectAtIndex: 0];
NSString *result = [match substringNamed:#"ImageURL"];
// : http://test.com/hello.jpg
}
It's easy to find all named capture values from a matches array. Does someone know how to do in RegexKit? Thanks.
Take a look at the documentation under Enumerating all the Matches in a String by a Regular Expression. Specifically, you want to learn about the RKEnumerator class.