Cocoa Touch: Circumventing UITableViewCell Redraw Issues with Multithreading

In your career as a Cocoa or Cocoa Touch developer, every now and then you’ll encounter an issue with something Apple has written. Whether it’s a full-blown bug, something that doesn’t work quite how you’d expect it to, or a minor inconvenience, it happens. When it does, naturally the first thing you do is file a bug report (right?). After that, though, you need to do something about it. This usually occurs right when a project is due, so often we can’t wait for Apple’s engineering teams to fix the problems (or tell you that you’re wrong). This post is an example of using KVO to get around the problem without worrying about it anymore.

The Problem: In iOS, if you create a UITableViewCell and return it to the table view in its data source’s -tableView:cellForRowAtIndexPath: method, but then return later (say, after doing some background processing) to add an image to the cell’s imageView, you don’t see anything! Why? Well, it looks like either the image view isn’t added to the cell’s view hierarchy if you don’t immediately add an image or there’s some other bug in the UITableViewCell implementation. I don’t think it’s a bug, I think it’s just a side effect of an optimization; if there’s no image, why add it to the cell?

So how do we fix it? Well, a simple call to -setNeedsLayout gets the cell to fix itself quite nicely. But we shouldn’t have to do that from our table view data source—that has a bit of code smell to it. Lines like that quickly get overused, with programmers calmly stating, “I don’t know why, but we always do that.” No, a better solution is to get the cell to handle this problem on its own.

We’ll create a subclass of UITableViewCell and use KVO. When we create the cell, we’ll register for KVO notifications with the on the image view whenever its image property is modified—but we’ll send the option to include the old value in the change dictionary. When we receive the notification, we’ll look at that dictionary, and if the old value was nil, then we’ll send self a -setNeedsLayout message. This avoids having to do it in other classes, and only does it when necessary. We simply set it and forget it.

Ta-da.

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:

[sourcecode language=”objc”]- (void)loadAwesomeURL
{
NSString *awesomeURI = @"http://www.awesomeexample.com/?output=JSON";
NSURL *awesomeURL = [NSURL URLWithString:awesomeURI];
NSURLRequest *awesomeRequest = [NSURLRequest requestWithURL:awesomeURL];

NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:awesomeRequest
delegate:self];

[theConnection start];
}

– (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[myMutableData appendData:data];
}

– (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self processTheAwesomeness];
}[/sourcecode]

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:

[sourcecode language=”objc”]- (void)loadAwesomeURL
{
NSString *awesomeURI = @"http://www.awesomeexample.com/?output=JSON";
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
returningResponse:&response
error:&error];

[self processTheAwesomeness];
});
}[/sourcecode]

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.

What Every Designer Should Know About iOS

Working with designers over the years, I’ve seen a few areas where the world of a designer and the world of a developer merge very well, and a few areas where they don’t. Photoshop comps that lead to sliced assets with non-localized text on them, storing a vertical gradient in a 1,024 × 1,024 JPEG image, Retina Display graphics that don’t match up to their non-Retina Display versions, and other places where I feel that a little bit of knowledge about iOS would go a long way. So, I’ve prepared this piece on what every designer should know before working with an iOS project.

  1. Apple Controls Everything.
    Literally. Since there’s no getting around this fact, we might as well start with it now. When your developer works with iOS, she’s using Apple’s tools to run on Apple’s operating system. So when she tells you that, for instance, a navigation bar can accept a tint color but not a custom gradient or an image, that’s because the Apple-provided version has those restrictions. Normally this isn’t an issue, but a designer needs to be prepared to provide their art in several different formats. For a tab bar, for instance, icons need to be (around) 30 × 30 pixels and filled out in the alpha channel.
  2. The Retina Display is not for layout.
    I think the best example of my last point above is the Retina Display. When it came out, developers started asking their designers for double-sized versions of their assets. Every image you provided for the original product needed to be resized. But the important thing to note about the Retina Display for a designer is not that suddenly there are two screen sizes to worry about on the iPhone. In fact, that can lead to catastrophe. When you design for the iPhone, you still create according to a 320 × 480 point screen. The Retina Display, unlike the regular display, happens to have two pixels per point. So when you make your assets, you have to design around the smaller size, but then take your assets and make a version exactly twice as large. This needs to be exact because the developer isn’t specifying the double-sized art or layout—in fact, they don’t specify anything. The art is simply named with an @2x suffix and iOS loads it in automatically.
  3. Things Change.
    When the Retina Display came out, that was a big change for designers (and developers). Apple can do this at any time. Tomorrow morning, Apple could announce a new iPhone Nano with a smaller screen or an iPad Pro with a Retina Display screen. If the screen size changes beyond a certain threshold, then developers will need to re-work their applications’ UI to accomodate. If that happens, your developer will be asking you for new assets, and he’ll want them immediately. If you saved everything in Photoshop six months ago and forgot what exactly you did to style everything, it’s going to be a long week. That’s why I recommend working in vector art for all but the most photorealistic elements (like skeuomorphism). If your work is in vector art and the developer suddenly needs assets at 150% of the original size, you re-export as .PNG, send it to the developer, and go back to doing whatever it is designers do in their free time.
  4. Push Your Developer.
    iOS has very sophisticated drawing abilities. If you want the background of a certain UI element to have a gradient, you might generate that gradient at the size of the element, then send it to the developer. If you know that the gradient can be stretched horizontally, you might send a one-pixel-wide version of it, instead. But you can also just tell the developer, “Draw a gradient from this color to this color and use it here.” This applies to more advanced drawing as well—need a circle with a dark-blue fill at 80% opacity, stroked with a 3-point thick, white line? The developer can draw it in code. This has the advantage of working at any resolution and being extremely changeable. Decide tomorrow morning that you want the color of the circle a bit lighter? Instead of sending the developer a new image, send him a new color and have him draw it differently. I called this tip “push your developer” because not every developer is as comfortable as the next with more advanced drawing, but I firmly believe that the more drawing you can do in code, the better.
  5. Spend Time on the Icon.
    The app’s icon is the first thing a user sees when they’re browsing the App Store. A beautiful, well-conceived icon can do wonders for an app. There are plenty of resources online for iOS icon design, so if you’re not sure where to begin, just head to Google.
  6. Standards are High.
    The most successful iOS applications have a level of beauty to them that other apps just can’t match. Utilitarian layouts with spartan design work, and if your client is an enterprise looking for an internal app, are appropriate, but won’t help the app. Your goal should be to make the app successful because of your design, not in spite of it.

Fun With the Objective-C Runtime: Run Code at Deallocation of Any Object

Update: This post is getting some attention lately, so I’ve updated it a bit to be less incorrect.

Sometimes when you’re debugging an application, especially one that you’ve inherited, you find yourself wondering when an object is released. Autorelease pools only compound the problem, delaying the actual release until the run loop is idle. In this post, I’ll show you how to take advantage of new features in the Objective-C runtime to run arbitrary code when any object—whether it’s your own or a part of Apple’s frameworks—is deallocated.

We’ll be taking advantage of the Objective-C runtime’s new associated objects behavior. When you associate an object with another object using retain or copy semantics, the runtime automatically handles releasing it at the appropriate time. So, if we want one object to be released when another object is deallocated, we simply associate them:

[sourcecode gutter=”false” language=”objc”]id objectToBeDeallocated;
id objectWeWantToBeReleasedWhenThatHappens;

objc_setAssociatedObject(objectToBeDeallocted,
someUniqueKey,
objectWeWantToBeReleasedWhenThatHappens,
OBJC_ASSOCIATION_RETAIN);[/sourcecode]

Now, when objectToBeDeallocated is deallocated, objectWeWantToBeReleasedWhenThatHappens will be sent a -release message automatically. The association policy passed as the last parameter to the function can be one of the following:

OBJC_ASSOCIATION_ASSIGN No memory management; the value is simply assigned.
OBJC_ASSOCIATION_RETAIN_NONATOMIC Retains the object non-atomically.
OBJC_ASSOCIATION_COPY_NONATOMIC Copies the object non-atomically.
OBJC_ASSOCIATION_RETAIN Retains the object atomically.
OBJC_ASSOCIATION_COPY Copies the object atomically.

Obviously, using OBJC_ASSOCIATION_ASSIGN won’t work for us, since it won’t cause the object to be retained. We also don’t want to use either of the copy policies, since we only want one copy of our objects around. For this example I’ll be using OBJC_ASSOCIATION_RETAIN, but not over OBJC_ASSOCIATION_RETAIN_NONATOMIC for any compelling reason.

Now that we know how to release an object when another is deallocated, we need to create an object to run arbitrary code at deallocation time. Blocks are an excellent tool for this, so I created a dead-simple class, JKBlockExecutor, to handle the running of the block:

[code language=”objc”]typedef void (^voidBlock)(void);

@interface JKBlockExecutor : NSObject {
voidBlock block;
}

@property (nonatomic, readwrite, copy) voidBlock block;

– (id)initWithBlock:(voidBlock)block;

@end

@implementation JKBlockExecutor

@synthesize block;

– (id)initWithBlock:(voidBlock)aBlock
{
self = [super init];

if (self) {
block = Block_copy(aBlock);
}

return self;
}

– (void)dealloc
{
if (block != nil) {
block();
Block_release(block);
}

[super dealloc];
}

@end[/code]

Now that we can pass arbitrary code to a JKBlockExecutor (and if you have a better name I’m all ears), we can make a category on NSObject to make the association for us:

[code language=”objc”]const void *runAtDeallocBlockKey = &runAtDeallocBlockKey;

@interface NSObject (JK_RunAtDealloc)

– (void)runAtDealloc:(voidBlock)block;

@end

@implementation NSObject (JK_RunAtDealloc)

– (void)runAtDealloc:(voidBlock)block
{
if (block) {
JKBlockExecutor *executor = [[JKBlockExecutor alloc] initWithBlock:block];

objc_setAssociatedObject(self,
runAtDeallocBlockKey,
executor,
OBJC_ASSOCIATION_RETAIN);

[executor release];
}
}

@end[/code]

So, how do you use it? The following example prints “Deallocating foo!” when foo is deallocated:

[objc]NSObject *foo = [[NSObject alloc] init];

[foo runAtDealloc:^{
NSLog(@"Deallocating foo!");
}];

[foo release];[/objc]

And that’s all there is to it!

Well, almost. There is one gotcha that I must warn you about: don’t access the object from within the block. There are two reasons. First, I’m not sure where in the deallocation process the Objective-C runtime releases its associated objects, so accessing the object may result in a crash. Second, if you reference the object from within the block, the block will retain the object. This causes a retain cycle where the block and the object each own each other, so neither will ever be released. If you absolutely must reference your object (at your own risk), then do it like so:

[objc]NSObject *foo = [[NSObject alloc] init];

__block id objectRef = foo;

[foo runAtDealloc:^{
NSLog(@"Deallocating foo at address %p!", objectRef);
}];

[foo release];[/objc]

Using the __block storage qualifier on an Objective-C object causes the runtime to avoid retaining the object, since the dymanics of object retain counts inside of blocks would be far too hairy to manage automatically. Seriously, though: don’t do it unless you absolutely must.

So there you have it: a quick and dirty category on NSObject to run arbitrary code at deallocation. I don’t really see a use it for it in production code, but on those occasions when you’re debugging someone else’s memory management, this could be handy. Since it uses blocks and associated objects, you’ll need to be running Mac OS X Snow Leopard (64-bit) or later or iOS 4.0 or later.