Working with JSON in iOS

Note from author: This is a learning note of Working with JSON in iOS 5 Tutorial written by Ray Wenderlich.

JSON is a simple human readable format that is often used to send data over a newtork connection.

For instance, if you have a Pet object with member variables name, breed, and age, the JSON representation would simply be:

{"name" : "Dusty", "breed": "Poodle", "age": 7}

The reason JSON is important is that many third parties such as Google, Yahoo, or Kiva make web services that return JSON formatted data when you visit a URL with a specified query string.

Parsing JSON from the Web

First, we need to download the JSON data from the web, which will implement with GCD to avoid blocking the main thread as this process is usually time-consuming.

 1 #define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 
 2 #define kLatestKivaLoansURL [NSURL URLWithString:@"http://api.kivaws.org/v1/loans/search.json?status=fundraising"]
 3 
 4 dispatch_async(kBgQueue, ^
 5 {
 6     NSData* data = [NSData dataWithContentsOfURL:kLatestKivaLoansURL];
 7     [self performSelectorOnMainThread:@selector(fetchedData:) 
 8                            withObject:data 
 9                         waitUntilDone:YES];
10 });

In our case the JSON file is relatively small so we‘re going to do the parsing inside fetchedData: on the main thread. If you‘re parsing large JSON feeds (which is often the case), be sure to do that in the background.

 1 - (void)fetchedData:(NSData *)responseData 
 2 {
 3     //parse out the json data
 4     NSError *error;
 5     NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData
 6                                                          options:kNilOptions 
 7                                                            error:&error];
 8     NSArray *latestLoans = [json objectForKey:@"loans"];
 9     NSLog(@"loans: %@", latestLoans);
10 }

NSJSONSerialization has a static method called JSONObjectWithData:options:error that takes an NSData and gives you back a Foundation object – usually an NSDictionary or an NSArray depending what do you have at the top of your JSON file hierarchy.

Parsing Options

kNilOptions is just a constant for 0. Here is the list of available options:

  • NSJSONReadingMutableContainers 

        The arrays and dictionaries created will be mutable. Good if you want to add things to the containers after parsing it.

  • NSJSONReadingMutableLeaves

        The leaves (i.e. the values inside the arrays and dictionaries) will be mutable. Good if you want to modify the strings read in, etc.

  • NSJSONReadingAllowFragments

        Parses out the top-level objects that are not arrays or dictionaries.

So, if you‘re not only reading, but also modifying the data structure from your JSON file, pass the appropriate options from the list above to JSONObjectWithData:options:error:.

Generating JSON Data

Here we‘ll build an NSDictionary called info where we store the loan information as who, where, and what in different keys and values.

// build an info object and convert to json
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:loan[@"name"], @"who",
                                                [(NSDictionary*)loan["location"][@"country"], @"where",
                                                                @(outstandingAmount), @"what", nil];
// convert object to data
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:info
                                                   options:NSJSONWritingPrettyPrinted 
                                                     error:&error];

NSJSONWritingPrettyPrinted - If you want to send the JSON over the Internet to a server use kNilOptions as this will generate compact JSON code, and if you want to see the JSON use NSJSONWritingPrettyPrinted as this will format it nicely.

Integrating Objects and JSON

In fact, for convenience, we can use category to extend NSDictionary, NSArray, NSString, and NSData with methods to convert to and from JSON data.

@interface NSDictionary (JSONCategories)
+ (NSDictionary *)dictionaryWithContentsOfJSONURLString:(NSString *)urlAddress;
- (NSData *)toJSON;
@end
 
@implementation NSDictionary (JSONCategories)
+ (NSDictionary *)dictionaryWithContentsOfJSONURLString:(NSString *)urlAddress
{
    NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString: urlAddress]];
    __autoreleasing NSError* error = nil;
    id result = [NSJSONSerialization JSONObjectWithData:data 
                                                options:kNilOptions error:&error];
    if (error != nil) return nil;
    return result;
}
 
- (NSData *)toJSON
{
    NSError* error = nil;
    id result = [NSJSONSerialization dataWithJSONObject:self options:kNilOptions error:&error];
    if (error != nil) return nil;
    return result;    
}
@end

So with this category fetching JSON from the web becomes as easy as:

NSDictionary  myInfo = [NSDictionary dictionaryWithContentsOfJSONURLString:@"http://www.yahoo.com/news.json"];

And of course on any of your NSDictionary objects you can do:

NSDictionary* information =  [NSDictionary dictionaryWithObjectsAndKeys:@"orange", @"apple", @"banana", @"fig", nil];
NSData *json = [information toJSON];

Pretty cool and readable code. Now of course you can also extend NSMutableDictionary with the same dictionaryWithContentsOfJSONURLString: method, but in there you‘ll have to pass NSJSONReadingMutableContainers as options – so hey, NSMutableDictionary could be initialized with JSON too, and it‘ll hold mutable data.

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。