MobiDevDay Presentation Slides

I gave a presentation on blocks and Grand Central Dispatch today at MobiDevDay. You can download the slides at SlideShare.

Looking for more reading about blocks? Here are some more resources:

Also, as we saw in the presentation, check out cdecl.org to cheat!

UPDATE: Looking for example code? I’ve put some of the code that went into the slides up on GitHub. It’s light, but it also includes a .PDF version of the presentation.

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.

Apple Doesn’t Like “Die, You Gravy-Sucking Pig-Dog!”

There’s a relatively well-known Easter egg in BSD’s shutdown.c: a function named die_you_gravy_sucking_pig_dog. It turns out that Apple doesn’t care to have such uncouth function names floating around, so they re-defined it:

#ifdef __APPLE__
void log_and_exec_reboot_or_halt(void);
#else
void die_you_gravy_sucking_pig_dog(void);
#endif

Sure, it does the same thing, but I don’t think log_and_exec_reboot_or_halt has the same panache.

WordPress 3.0

I’ve updated the site to WordPress 3.0. So far all is well; I’ll likely create a new post type (excellent new feature) for software once I have more software to be creating posts about.

Big Nerd Ranch

Big Nerd Ranch Cabin
My cabin at the Big Nerd Ranch.

Hopefully, I will continue to improve the content of this site in the months to come. To that end—among others—I’m at the Big Nerd Ranch in Atlanta, Georgia for their Advanced Mac OS X Programming course this week. I’m very excited and hope to learn as much as I can possibly fit into my brain.