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.

Apple Surveying 32-Bit Third-Party Kernel Extensions

Today I noticed something new in my LaunchDaemons folder: /Library/LaunchDaemons/com.apple.third_party_32b_kext_logger.plist. It starts a Ruby script (/usr/libexec/third_party_32b_kext_logger.rb) when your Mac starts up that (and I could be totally wrong, as I don’t know Ruby) appears to use /usr/sbin/kextfind -system-extensions to identify third-party kernel extensions (e.g. kernel extensions for which the identifier does not begin with com.apple) that exist only in i386 or PPC forms. It makes sense why Apple would do this, as a move to 64-bit only would be in keeping with their typical attitude on leaving old hardware platforms behind, but this particular file is odd in that it’s in /Library/LaunchDaemons and not /System/Library/LaunchDaemons, where most Apple-created jobs are. Maybe this was a task given to a programmer new at Apple who was unfamiliar with the typical folder hierarchy on a Mac, but this smells odd. The only result I found for it in Google was this Apple Support forum post.
So, I did some investigation, and found that it uses the domain “com.apple.kexts.32bitonly” with the defaults command, and in my system log is this line:

/var/log/system.log:Mar 22 19:31:30 Jeff-Kelleys-MacBook defaults[3439]: \nThe domain/default pair of (com.apple.kexts.32bitonly, lastRan) does not exist

That is reason enough for me to believe that it’s installed as a part of Mac OS X 10.6.7, as that message signifies its last run time (the script quits if it’s been less than a week since it last ran). So, being the diligent former sysadmin that I am, I looked at the 10.6.7 update’s files, and didn’t see anything (else) of note. I don’t see a point in the script that reports this to Apple, so I don’t know if this constitutes a breach of privacy on their part, but it’s interesting nonetheless that it would appear that Apple is gauging whether or not they can leave 32-bit kernel extensions behind with minimal customer fuss.

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?

Cocoa Touch Tutorial: Using Grand Central Dispatch for Asynchronous Table View Cells

One of the problems that an iOS developer will often face is the performance of table view cells. Table view cells are loaded on-demand by the UITableView that they’re a part of; the system calls ‑cellForRowAtIndexPath: on the table view’s dataSource property to fetch a new cell in order to display it. Since this method is called (several times) while scrolling a table view, it needs to be very performant. You don’t have very much time to provide the system with a table view cell; take too long, and the application will appear to stutter to your users. This kills the immersion of your application and is an instant sign to users that the application is poorly-written. I guess what I’m saying is that this code needs to be fast. But what if something you need to do to display the table view cell takes a long time—say, loading an image?

In my MobiDevDay presentation a couple of weeks ago, I illustrated a solution to this problem: Grand Central Dispatch. GCD, Apple’s new multiprocessing API in Mac OS X Snow Leopard and iOS 4, is the perfect solution for this problem. Let’s take a look at how it works.

Grand Central Dispatch operates using queues. Queues are a C typedef: dispatch_queue_t. To get a new global queue, we call dispatch_get_global_queue(), which takes two arguments: a long for priority and an unsigned long for options, which is unused, so we’ll pass 0ul. Here’s how we get a high-priority queue:

[sourcecode language=”objc” gutter=”false”]dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);[/sourcecode]

It’s pretty straightforward. To use this queue, we add blocks of code onto it. Typically this is done with blocks (Apple’s new code encapsulation extension to the C language), though it can be done with C functions. To submit a block onto a queue for execution, use the functions dispatch_sync and dispatch_async. They both take a queue and a block as parameters. dispatch_async returns immediately, running the block asynchronously, while dispatch_sync blocks execution until the provided block returns (though you cannot use its return value). Here’s how we schedule some code onto a queue (we’ll assume this code runs after our previous example, so queue is already defined):

[sourcecode language=”objc” gutter=”false”]dispatch_async(queue, ^{
NSLog(@"Hello, World!");
});[/sourcecode]

It’s very easy to forget the ); at the end of that line, so be careful.

How does this apply to table view cells? Let’s take a look at a typical scenario for loading images from disk:

[sourcecode language=”objc” firstline=”33″]- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"ExampleCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}

// Get the filename to load.
NSString *imageFilename = [imageArray objectAtIndex:[indexPath row]];
NSString *imagePath = [imageFolder stringByAppendingPathComponent:imageFilename];

[[cell textLabel] setText:imageFilename];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
[[cell imageView] setImage:image];

return cell;
}[/sourcecode]

The problem with that code is that creating image blocks until ‑imageWithContentsOfFile: returns. If the images are especially large, this is catastrophic. Modifying this code to use Grand Central Dispatch is simple:

[sourcecode language=”objc” firstline=”33″]- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}

// Get the filename to load.
NSString *imageFilename = [imageArray objectAtIndex:[indexPath row]];
NSString *imagePath = [imageFolder stringByAppendingPathComponent:imageFilename];

[[cell textLabel] setText:imageFilename];

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);

dispatch_async(queue, ^{
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];

dispatch_sync(dispatch_get_main_queue(), ^{
[[cell imageView] setImage:image];
[cell setNeedsLayout];
});
});

return cell;
}[/sourcecode]

First, we create our image asynchronously by using dispatch_async(). Once we have it, however, we have to come back to the main thread in order to update our table view cell’s UI (all UI updates should be on the main thread, unless you like reading crash reports). GCD has a function to get the main queue—analogous to the main thread—called dispatch_get_main_queue(). We can dispatch a block to that thread to update the UI.

By making this simple modification, we can very easily improve the performance of our table view. There are a few steps remaining, however, and this method has one serious shortcoming: if the cell is re-used by the time the image loads, it can load the wrong image into the cell. To get around this, it would be better to cache the images in an array or a dictionary (just be sure to release it in your view controller’s ‑didReceiveMemoryWarning: method). That said, this is an example of something you can do quite easily to improve the performance of your application. The better it performs, the more your users will like it, and that’s the ultimate goal.

The code used in this post is available as a GitHub repository.

iPhone Programming: Hard Mode

After a conversation with some co-workers, I discussed how it would be technically possible to write an iPhone app using only a main.m file—no separate class files. This post is the result of that. It’s definitely doable, but not something I’d ever recommend for shipping code.
The code is explained below, but you can get the full source in my public GitHub repository.

Getting Started

By default, an iPhone application template gives you a main.m file, but it’s pretty basic:

[sourcecode language=”objc” firstline=”9″]#import <UIKit/UIKit.h>

int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}[/sourcecode]

To go from that code to running your application, a few things happen, mostly in UIApplicationMain. Its last argument, typically nil, is a pointer to an NSString that specifies the class name of the application delegate. Normally, your Info.plist file specifies a nib file (the keys NSMainNibFile or NSMainNibFile~ipad), which in turn specifies the application delegate, instantiates it, etc.

So, first, delete the MainWindow.xib file, then all other class files (MyCoolAppDelegate.h and MyCoolAppDelegate.m, for instance). There should be three files left in the iPhone application: your Prefix.pch file (which we could technically do without), main.m, and your Info.plist file.

The Fun Begins

Administrivia: Creating Strings

Since, as a part of the exercise, we don’t want to use Objective-C, I also decided against using any constant NSStrings (@"Hello, World!" and the like). To create a string, then, we’ll use CFStrings. I created a macro to create one from a C string using ASCII encoding:

[sourcecode language=”objc” firstline=”16″]#define JK_EasyCFString(X)
(CFStringCreateWithCString(kCFAllocatorDefault, (X), kCFStringEncodingASCII))[/sourcecode]

Don’t forget to call CFRelease() when you’re done with it, though.

Creating a Class

We need to modify the call to UIApplicationMain to include our application delegate class if we want this app to be anything more than a blank screen. What class name can we give it, though? We’ll need to create a class, and we’ll call it “HardModeAppDelegate.”

[sourcecode language=”objc” firstline=”41″ highlight=”42″] // Create a class to serve as our application delegate.
Class appDelegate = objc_allocateClassPair(NSClassFromString((id)NSObjectString), "HardModeAppDelegate", 0);[/sourcecode]

The first argument is a toll-free bridged CFString that specifies NSObject as the superclass, then we pass in the name of the class as a C string and 0 for the number of extra bytes we want (which is nearly always zero). Now let’s set it up a bit:

[sourcecode language=”objc” firstline=”44″ highlight=”46,49,50,51,52,65″] // Conform to the UIApplciationDelegate protocol.
Protocol *appDelegateProto = NSProtocolFromString((id)UIApplicationDelegateString);
class_addProtocol(appDelegate, appDelegateProto);

// Add methods.
SEL applicationDidFinishLaunchingWithOptions = NSSelectorFromString((id)appDidFinishLaunchingOptionsString);
class_addMethod(appDelegate,
applicationDidFinishLaunchingWithOptions,
(IMP)UIApplicationDelegate_ApplicationDidFinishLaunchingWithOptions,
"v@:@@");

SEL dealloc = NSSelectorFromString((id)deallocString);
class_addMethod(appDelegate,
dealloc,
(IMP)appDelegate_dealloc,
"v@:");

// Add an instance variable for the window.
class_addIvar(appDelegate,
"window",
sizeof(id),
log2(sizeof(id)),
"@");

// Now that we’ve added ivars, we can register the class.
objc_registerClassPair(appDelegate);[/sourcecode]
That code is the same as writing an @interface block for a new class, setting up ivars, conforming to protocols, and defining instance methods, but done using the runtime calls instead. Methods are actually C functions, but with two arguments prepended to the argument list: id self and SEL _cmd. Those arguments are actually passed to every Objective-C method, but usually hidden.

Custom Message Sending

The rest of the application is more of this bootstrapped Objective-C in C, but there are a few wrinkles worth discussing, most notably the use of objc_msgSend with methods that return other than id and/or have additional arguments beyond self and _cmd. For instance, to call -bounds on a UIScreen object, I had to cast the return type of objc_msgSend to CGRect:
[sourcecode language=”objc” firstline=”134″ highlight=”135″]CGRect (*msgSendBounds)(id self, SEL _cmd);
msgSendBounds = (CGRect(*)(id, SEL))objc_msgSend_stret;[/sourcecode]
Similarly, when calling -initWithFrame: on a UIWindow or UILabel, I casted it to take in a CGRect argument:
[sourcecode language=”objc” firstline=”141″ highlight=”142″]id (*msgSendCGRect)(id self, SEL _cmd, CGRect rect);
msgSendCGRect = (id(*)(id, SEL, CGRect))objc_msgSend;[/sourcecode]

Accessing Instance Variables

In my implementation of the HardModeAppDelegate class’s -dealloc method, I need to access the window instance variable to send it a -release message. Using the Ivar type and the object_getIvar function, it becomes easy:
[sourcecode language=”objc” firstline=”196″]Ivar windowIvar = class_getInstanceVariable(self->isa, "window");
id window = object_getIvar(self, windowIvar);[/sourcecode]

So what do we have?

To be clear, this is not writing an iPhone app without using Objective-C, per se. The runtime is still being used, messages are being sent, all that. But it is an illustration of some of the heavy lifting that the runtime does for you. I would caution against adopting this practice for real, shipping apps.