CocoaConf Columbus 2012 Slides and Code

Yesterday I gave a talk on concurrency in OS X and iOS at CocoaConf Columbus. As promised, here are the slides and code:


GCD Example Updated (Now With More Speed!)

Due to popular demand, I’ve updated my GCD example from previous talks to include a few things to make the example not only do something on a background queue, but also snappy. It should scroll much better now. A quick rundown of what changed:

  • Images are now resized. Since the example uses wallpaper-sized images, there’s no sense in not resizing them to go on a 44-pixel-tall table view cell. I’m using the popular image-resizing routines from Trevor’s Bike Shed to do the resizing with a nice interpolation quailty.
  • Those resized images are now cached. I use an NSCache to store the images. If the app receives a memory warning, it’ll jettison all of the cached images, but if you’re just scrolling up and down this is a quick and dirty way to cache the images. I had never really used NSCache before, so this was a good excuse to try it.
  • I’m at CocoaConf in that state down to the South today, so this post has been brought to you by late-night hotel room caffeine. I made some other changes to the project to deal with a weird table view cell bug that I’ve submitted to Apple; a post on that is coming up next!

Asynchronous Synchronous Requests: Effortless Networking Code

Today I showed a couple of people at work a technique I use to do asynchronous URL loading in iOS, and the response on Twitter was great, so I’ve written it up for everybody. If you’re used to using ASIHTTPRequest or rolling your own NSURLConnection delegates, hopefully this method will be a breath of fresh air.

The Problem: When you want to load something from the Internet, you don’t want to block your UI—especially when iOS might just kill your app for doing so—but writing delegate code is a pain. You have to remember which delegate methods get called in what order, to set yourself as the delegate (can’t tell you how many times that’s tripped me up), and handling multiple simultaneous connections with one delegate is… tricky, at best.

The Solution: Use Grand Central Dispatch. Maybe I just love GCD too much and this is me seeing everything as a nail, but let’s look at the following code for loading a URL:

- (void)loadAwesomeURL
    NSString *awesomeURI = @"";
    NSURL *awesomeURL = [NSURL URLWithString:awesomeURI];
    NSURLRequest *awesomeRequest = [NSURLRequest requestWithURL:awesomeURL];

    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:awesomeRequest

    [theConnection start];

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    [myMutableData appendData:data];

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
    [self processTheAwesomeness];

That sucks. Three methods, and I didn’t even do any error handling! There has to be a better way. NSURLConnection offers a synchronous method, but everybody knows you don’t use it… so let’s do exactly that. But since we want to make this asynchronous, we’ll use Grand Central Dispatch to wrap it in a dispatch_async() call:

- (void)loadAwesomeURL
    NSString *awesomeURI = @"";
    NSURL *awesomeURL = [NSURL URLWithString:awesomeURI];
    NSURLRequest *awesomeRequest = [NSURLRequest requestWithURL:awesomeURL];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
    dispatch_async(queue, ^{
        NSURLResponse *response = nil;
        NSError *error = nil;

        NSData *receivedData = [NSURLConnection sendSynchronousRequest:awesomeRequest

        [self processTheAwesomeness];

We can easily do error checking after the NSURLConnection call; simply check to see if receivedData is nil, cast response to an NSHTTPURLRequest and check its statusCode property, and if all else fails, check out error.

Note: I’ve received a fair amount of negative feedback on this article on Twitter, Reddit, and in the comments, and I feel like I ought to make a few points clear:

  • This is not the last networking solution you’ll ever need. Among other things, this does not support:
    1. Canceling the connection
    2. Running code when the connection is half-done
    3. Streaming data to a file for large downloads
  • This is a quick example. It’s mainly designed to illustrate dispatch_async() as a wrapper for synchronous APIs.
  • It isn’t good for multiple connections. You’ll want a custom dispatch queue for that.
  • It doesn’t run on the main thread. If you’re updating your UI, you’ll need to do that on the main thread.

iOS Programming for Multicore Processors

With the impending release of the iPad 2, understanding how to program multithreaded applications will quickly become paramount as applications continue to push the envelope to make immersive experiences with high-performance computation. Now, without actually having a multicore iPad in my hands, I can’t say exactly how the system will behave, but there are a few best practices we should all be aware of when writing iOS code:

  • Using Core Data? You can’t share access to an NSManagedObjectContext across multiple threads, dispatch queues, or NSOperation queues, so for each one you’ll need to create a new instance. Similarly, don’t pass an NSManagedObject or subclass thereof between threads. Give each of your objects a unique ID—CFUUID works well for this—and pass the ID around, pulling a new object out of your NSManagedObjectContext for each thread. It’s a pain, but that’s how to (safely) get around threading and Core Data.
  • Always call UIKit updates from the main thread. Whatever you’re doing to your user interface, be it updating a label, loading an image into an image view, anything that’ll be rendered to screen—and some things that won’t—should be run on the main thread. There are two main ways to do this:
    1. Use Grand Central Dispatch. Using dispatch_get_main_queue(), you can get a reference to the main queue and submit blocks to it for updating your UI. This is typically a clean, easy way to refactor existing code for thread-aware programming.
    2. Use -performSelectorOnMainThread:withObject:waitUntilDone: and friends. This has the drawback of only working for methods that take one or zero Objective-C objects as arguments, but can be a quick and easy way to use fire-and-forget methods like -reloadData on UITableView.
  • Think about how you declare your properties. How many people have been using atomic properties? Before now, not many. In fact, before now, it was typically useless, as the chances of something interrupting your accessor methods was pretty low. Now, though, if you’re planning on accessing an object from multiple threads, you really need to control access to your properties.
  • Use locks. Locks, long the scourge of the multithreaded-code author, are simply essential for some parts of multithreaded programming. Whether you’re using NSLock or a lower-level lock, or even something like Grand Central Dispatch’s counting semaphore type, dispatch_semaphore_t, protect critical regions of your code from multiple accessors with (carefully-thought-out) locked access.

This list is by no means exhaustive, and Apple can do a lot to make this irrelevant (such as make UIKit threadsafe, which would be a killer iOS 5.0 feature), but with the iPad 2’s arrival, developers can no longer assume safety from threading problems. Be sure also to read Apple’s Threading Programming Guide to get anything I’ve left out.

It also makes a great excuse to buy an iPad 2. I mean, you need to test this, right?