Categories
Development iOS Mac

Swift, REST, and JSON

I’m fond of a site called The Pastry Box Project. It’s a collection of thoughts and stories by a bunch of great writers, but that’s not why I mention it. I mention it because I noticed they had a nice, simple, REST API. Nifty!

PastryKit

Since I really enjoy writing code that communicates with services, and I needed a little project to learn some Swift, I thought I’d write a couple classes, I call PastryKit, that implement the Pastry Box REST API in Swift.

PastryKit is just two classes:

  1. PastryKit – Allows you to communicate with the Pastry Box REST API.
  2. Pastry – This is an entry returned by a call to PastryKit.

You can read more about The Pastry Box API on their site.

private func showPastryBaker() {
     var pastryKit = PastryKit();
     pastryKit.thoughtsByBaker("mike-monteiro", completionHandler:{(pasteries, error) in
          if (nil != error) { println(error) }
          if (nil != pasteries) { println(pasteries) }
     });
}

The Heavy Lifting

Most of the “heavy lifting” is performed in one place in PastryKit.swift in the private getWithIngredient function. It makes use of NSURLSession, which was introduced in iOS 7. Go find that function if you’d like to see how to do an HTTP GET in Swift. This is a simple case, it doesn’t require any authentication, or messing around with headers, and it only does GET’s. Doing a POST, PATCH or DELETE would, of course, require some changes, but you get the idea.

    /// getWithIngredient - worker method that does all gets
    private func getWithIngredient(ingredient: String?, completionHandler: (([Pastry]!, NSError!) -> Void)?) {
        let url = ((ingredient) != nil) ? NSURL(string: PastryBoxUrl + ingredient!) : NSURL(string: PastryBoxUrl)
        let request = NSURLRequest(URL: url!)
        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
        let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
        let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler:{(data, response, error) in
            if (error == nil) {
                var conversionError: NSError?
                var ingredientsArray: NSArray = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.AllowFragments, error:&conversionError) as NSArray
                if (conversionError == nil) {
                    var pasteries = Pastry.pastryArrayFromNSArray(ingredientsArray)
                    if (completionHandler != nil) {
                        completionHandler!(pasteries, nil)
                    }
                }
                else {
                    println(conversionError)
                    if (completionHandler != nil) {
                        completionHandler!(nil, conversionError)
                    }
                }
            }
            else {
                println(error)
                if (completionHandler != nil) {
                    completionHandler!(nil, error)
                }
            }
        });
        
        task.resume()
    }

Go Get It!

The code is available on GitHub if you have need to get stuff from The Pastry Box Project in your Swift or Objective-C app.

Enjoy!

Categories
Development

Revisiting Objective-C, REST, and JSON

I get a lot of hits on this site for two posts.

  1. Objective-C REST and JSON
  2. Objective-C Objects from JSON

Both posts touch on using JSON to create Objective-C objects. The first one mostly talks about great Cocoa Libraries you can use to make REST calls and parse JSON results.

Since that time JSON parsing has become a part of iOS. In iOS 5 Apple introduced NSJSONSerialization.

For a presentation on REST and JSON to @NSSLO back in May I created a super simple project that used NSURL, NSMutableURLRequest, NSURLConnection, and NSJSONSerialization to call the iFixIt API.

If you’re interested in grabbing the project, it’s available on GitHub.

Will write C/C++ for food

The Code

Most of the RESTTest project is a boiler plate iOS application. There are a couple places in MasterViewController.m you should pay attention to and we’ll take a look at the iFixItBadges and the iFixItBadge classes.

The Basics

To get the ball rolling we make a call to a private method: getBadges.

- (void)getBadges; {
	NSURL *url = [NSURL URLWithString:@"http://www.ifixit.com/api/0.1/badges"];
	NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
                                                           cachePolicy:NSURLRequestReloadIgnoringCacheData 
                                                       timeoutInterval:10];
	if (request) {
		[request setURL:url];
		connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
	}
}

This method is pretty straight forward and uses three of the four classes we mentioned above; NSURL, NSMutableURLRequest, and NSURLConnection. That’s all it takes to do a simple(REST) HTTP GET call. Yes, it’s sample code, so it’s not complex and is not something you’d find in a shipping application as is. It would need some beefing up and it definitely changes if you’re going to do a POST, or DELETE call, not to mention the lack of authentication. I picked the badges call because it didn’t require authentication.

When we allocate and initialize NSURLConnection it takes off and starts doing the work. Notice we’ve specified self as the delegate, which means NSURLConnection will expect us to have implemented the NSURLConnectionDelegate Protocol.

The next method we’ll want to take a look at is connectionDidFinishLoading.

- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
	NSString* s = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
	NSLog(@"Received data %@", s);

    badges = [[IFixItBadges alloc] initWithData:receivedData];
    
    [self.tableView reloadData];
}

This is called by NSURLConnection when it’s finished receiving the response from our badges call. At this point we should have a nice JSON response to parse. Notice we’re working on receivedData, which is private and is built in the didReceiveData method. I’d recommend building the code and running it in the debugger to see how it works.

Back to connectionDidFinishLoading. We have our receivedData (an NSMutableData*), now we’re going to create an IFixItBadges object.

Creating objects from JSON

To review. We’ve called the iFixIt badges method and we’ve received our response data. Now we need to do something with it. Say hello to NSJSONSerialization.

- (id)initWithData:(NSData*)data;
{
    if ((self = [super init])) {
        badges = [[NSMutableArray alloc] init];
        
        NSError *error = nil;
        NSArray *resultData = [NSJSONSerialization JSONObjectWithData:data
                                                              options:kNilOptions
                                                                error:&error];
        if (resultData && nil == error && badges) {
            NSDictionary *badgesData = nil;
            NSEnumerator *resultsEnum = [resultData objectEnumerator];
            while (badgesData = [resultsEnum nextObject]) {
                IFixitBadge *badge = [[IFixitBadge alloc] initWithDictionary:badgesData];
                [badges addObject:badge];
            }
        }
    }
    
    return self;
}}

When we get our result back we create an iFixItBadges object, which is a collection of iFixItBadge objects. We could’ve just as easily used NSMutableDictionary or NSMutableArray to hold these objects.

Notice the use of NSJSONSerialization. One call. That’s all it takes to create an array of data we can then iterate over to create an iFixItBadge to add to our collection. Once the collection is created we tell the table view to reload itself using [self.tableView reloadData];

That’s it in a nutshell. If you have any questions about this, or find a problem, please feel free to leave a comment or send email to rob.fahrni@gmail.com.

Happy coding.

Categories
Development

Objective-C Objects from JSON

I was asked recently how to create an Objective-C Object from a JSON result returned by a RESTful service. Man, that’s a mouthful.

It’s actually fairly easy, especially if you make use of the excellent JSONKit by John Engelhart. The example below does just that.

For starters I created a simple Cocoa Application and changed main() so it returns 0, because we don’t need to show a window and have an event loop. Here’s a link to the complete main.m.

Next add JSONKit.m and JSONKit.h to your project, and build. That’s it. It should just work.

Here’s what the code does.

For starters we define some sample JSON. This is very rudimentary. The object contains a firstName and lastName field. This is meant to represent the data returned by our pretend REST service.

static NSString* const kSampleJSON = @"{\"firstName\": \"Rob\", \"lastName\": \"Fahrni\"}";

Next up we define a Person interface.

@interface Person : 
    NSObject
{
@private
    NSString* _firstName;
    NSString* _lastName;
}

@property (copy) NSString* firstName;
@property (copy) NSString* lastName;

- (id)initWithDictionary:(NSDictionary*)dict;
- (void)dealloc;

@end

Again, very simple. This Person interface has first name(_firstName) and last name(_lastName) members and is initialized by passing it an NSDictionary*. So far, it looks pretty easy, right? Right!

The next thing we need to do is implement Person. Once again, no rocket science here. It’s straight Objective-C.

@implementation Person

@synthesize firstName = _firstName;
@synthesize lastName = _lastName;

- (id)initWithDictionary:(NSDictionary *)dict;
{
    if ((self = [super init]))
    {
        _firstName  = [dict valueForKey:@"firstName"];
        _lastName   = [dict valueForKey:@"lastName"];
    }
    
    return self;
}

- (void)dealloc;
{
    [_lastName release];
    [_firstName release];
    
    [super dealloc];
}

- (NSString*)description
{
    // Overriding description allows you to print something meaningful
    // to the debug output window. In this case we'll print 
    // Rob Fahrni.
    return [NSString stringWithFormat:@"%@ %@\n", _firstName, _lastName];
}

@end

Ah! Now we’re getting somewhere. Notice the Person is constructed with an NSDictionary* that should contain at least two entries; firstName and lastName. Note “firstName” and “lastName” just so happen to match our simple JSON constant, defined as kSampleJSON. That’s because it’s the source of our data.

Something else of note is the method description. By overriding NSObject description we allow NSLog to dump something meaningful when we give an instance of Person as an argument. You’ll see that used below. It’s darned handy when you’re debugging.

UPDATE 12/31/2011: I noticed I’d used objectForKey instead of valueForKey when assigning to _firstName and _lastName.

Finally we can test our code to see what it does.

int main(int argc, char *argv[])
{
    // Pretend like you've called a REST service here and it returns a string.
    // We'll just create a string from the sample json constant at the top
    // of this file.
    NSString* responseJSON = [NSString stringWithFormat:@"%@", kSampleJSON];
    
    // 1) Create a dictionary, from the result string,
    // using JSONKit's NSString category; objectFromJSONString.
    NSDictionary* dict = [responseJSON objectFromJSONString];
    
    // 2) Dump the dictionary to the debug console.
    NSLog(@"Dictionary => %@\n", dict); 
    
    // 3) Now, let's create a Person object from the dictionary.
    Person* person = [[[Person alloc] initWithDictionary:dict] autorelease];
   
    // 4) Dump the contents of the person object
    // to the debug console.
    NSLog(@"Person => %@\n", person);

    return 0;
}

That’s all there is to it? Yep, that’s it! Pretty simple, right?

Categories
Development

Hello, rdd.me

Readability Blog: “One of the more useful tools in the Readability toolbox has been our link shortener, rdd.me. The interesting bit about rdd.me is simple: When an article is linked to through rdd.me, it offers up the availability to view the content in a clean, readable view.”

Get to building! If you need some Objective-C to talk to rdd.me, you’re in the right place.

Take a look at RFRddMe.

Categories
Development

Objective-C REST and JSON

Bringing in the HarvestThe first REST based code I wrote for the Mac and iOS was my P8 Library for ping.fm. That code is all NSRequest based and I learned a lot while doing it. Since that time I’ve done a couple more projects that consumed REST Services and XML or JASON.

To that end I thought I’d record some of the libraries I’ve run across. Some I’ve used, others are a curiosity.

REST Libraries

ASIHTTP – I’ve used this library a couple of times and I’m using it on a new project. I like it, but the developer that lovingly created it is giving up on it because people gave him too much crap. That’s a real shame, not only that he’s done with it, but that people would harass him so much he gave up on a very handy piece of code.

LRResty – A simple REST/HTTP client. Apparently this library was inspired by a Ruby implementation. I’m fairly certain this is the library I’ll be moving to this in the future.

RestKit – This library not only deals with retrieving data, it will also map it into Core Data. Pretty cool, and if you have need to cache data locally it would be worth looking at.

JSON

SBJson – A very nice JSON parser. It’s simple to use and includes handy categories for NSString and NSDictionary. It’s very simple to create a parser and operate on the results, just like you would an NSDictionary.

SBJsonParser* jsonParser = [[SBJsonParser new] autorelease];
id jsonObject = [jsonParser objectWithString:jsonString];

JSONKit – This is a parser I only recently discovered, and it’s known to be fast and efficient. It’s also super easy to use because of, you guessed it, categories. There’s a real nice one added to NSString.

NSDictionary* response = 
[[request responseString] objectFromJSONString];

See how easy that is to use? You simply invoke objectFromJSONString to get a fully parsed result jammed into an NSDictionary.