Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

iOS Quick Tip: Interacting with Web Services

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

At some point in your iOS development career, you will have the need to interact with a web service from within your app. You may need to access remote data, parse a social network feed, or even download some assets into your application. This quick tip will teach you to do so without using third party libraries!

There are some incredible third party libraries out there to help facilitate web service interactions, including ASIHTTPRequest, AFNetworking, and RESTKit. While these libraries are incredibly useful, sometimes they are a little bit overkill. They add quite a bit of unneeded code bloat to an app via extra variables in memory, and also modify your workflow to adjust to the workflow of each library.


Simplifying

I used to use some of these libraries (and more!) as a crutch. I felt using them sped up development time and reduced complexity. While this is true in many cases, these are not "one size fits all solutions". Additionally, you are adding complexity unless you fully understand everything under the hood of these libraries.

Today, I am going to show you a much simpler approach to interfacing with web services and downloading data from the web. I have recently used this approach in my new iOS MUD client Pocket MUD Pro to fetch remote audio, settings, and data. This approach involves using the "built-in" technologies for downloading, parsing and using remote JSON as well as assets such as images and sounds.


Fetching Remote Data

In iOS versions prior to 4, it was quite a pain to fetch data asynchronously. You usually had to create a full blown class dedicated to making requests and then another to parse and use the responses. With Grand Central Dispatch (GCD), you can now do this inline and keep your code short and clean. Here you will see some code that fetches a remote JSON document from the web:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_async(queue, ^{
        NSError *error = nil;
        NSURL *url = [NSURL URLWithString:@"http://brandontreb.com/apps/pocket-mud-pro/promo.json"];
        NSString *json = [NSString stringWithContentsOfURL:url
                                                  encoding:NSASCIIStringEncoding
                                                     error:&error];
        NSLog(@"\nJSON: %@ \n Error: %@", json, error);
    });

This code starts by fetching one of Apple's three dispatch queues that you are able to use for asynchronous execution and runs a block on the queue with default priority. You could just as easily have created your own queue. Either way, this allows our code to run in a separate thread from the main thread through the power of Grand Central Dispatch (GCD).

We then build the URL and stick it into the stringWithContentsOfURL:encoding:error: method of NSString to fetch the JSON data. Finally, the return string gets printed out along with the error (if there is one).

This approach is very rapid, but doesn't give you a ton of control. Although you know what an error might be, it doesn't allow you to specify a timeout in the event of an error. The default timeout is somewhere around 30 seconds. If you want some additional control over timeout and such, replace the string method with an NSURLConnection.


Parsing JSON

As of iOS 5, Apple has a built-in JSON parser which allows you to take a string containing JSON and convert it into an NSDictionary or an NSArray. In order to parse and use the JSON returned in the code above, add these lines before the end of the block:

if(!error) {
    NSData *jsonData = [json dataUsingEncoding:NSASCIIStringEncoding];
    NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData 
                                                                options:kNilOptions
                                                                  error:&error];
    NSLog(@"JSON: %@", jsonDict);
}

The NSJSONSerialization class will parse and convert a JSON string into an NSDictionary or NSArray depending on the format of your JSON. This makes your life much, much easier. Now you are able to use the values from the JSON string like this:

NSString *promo_url = [jsonDict objectForKey:@"promo_url"];

And there you have it! A very basic way to consume web services using ONLY native SDK classes. Now, on to something a little more interesting...images!


Fetching Remote Images

We can use the method described above to fetch any sort of remote media. For this example, I will show you how to download an image from the popular blog XKCD.

    dispatch_queue_t img_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(img_queue, ^{
        
        NSURL *url = [NSURL URLWithString:@"http://imgs.xkcd.com/comics/formal_logic.png"];
        NSError *error = nil;        
        NSData *image = [NSData dataWithContentsOfURL:url options:0 error:&error];
        
        if(!error && image && [image length] > 0) {
            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
            NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"image.png"];
            
            [image writeToFile:path options:0 error:&error];              
        }

Again, we start by getting a queue to run asynchronously on. Next, we fetch the image data using the dataWithContentsOfURL:options:error: method of NSData. Once we verify that we have returned some data, we grab a reference to the caches directory on disk and save the image.

And it's that simple! You can also use the fetched image right away by doing this:

UIImage *img = [UIImage imageWithData:image];

Conclusion

I hope this article has helped you to remove your crutch on third party libraries in order to interact with the web. You should now have the knowledge to create a full blown web application. If you have any questions or comments, please leave them here or write me on Twitter.

Happy Coding!

Advertisement