Consider the following main() method which you’ll find in most iPhone applications:

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

You might assume (as I did) that when an iPhone application ends, the above call to UIApplicationMain() will return and the rest of main() will run, eventually returning an integer. That assumption would be incorrect, however.

UIApplicationMain() never actually gets a chance to finish, nor do any of the statements that follow it have a chance to execute. When an iPhone OS application is closed (e.g., the user pushes the home button) the application is given a few seconds to run its -applicationWillTerminate method and then it calls the exit() system function. This makes sense, if you think about it: it’s more efficient to just stop the program and let the operating system free up all of its memory at once instead of running several individual -dealloc statements. Dump the whole trash bin instead of picking stuff out one-by-one, so to speak.

However, when I noticed this several months ago (while trying to run some logging and shut-down statements in main) I was very confused; the official Apple documentation for the UIApplicationMain() function said zilch about UIApplicationMain() never returning. In fact, while all the iPhone documentation obviously encouraged putting shutdown code inside the standard -applicationWillTerminate method, it said nothing about the fact that it’s essentially pointless to write any code after your call to UIApplicationMain() (aside from the return statement, necessary to keep the compiler happy).

After some collective head-scratching on developer forums someone observed that the documentation for NSApplicationMain()–the AppKit/Cocoa counterpart to UIApplicationMain()–did describe the exit(0) behavior. This prompted me to fill out a quick bug report requesting that Apple update the documentation. Fast-forward to today, when I randomly came across that documentation and noticed that it has been updated and my bug was closed. Who knows if I’m actually the one responsible for instigating the correction, but I’ll tell myself that I am.

Image used with permission from Landon Cahow, redzephyrdesign.com

Image courtesy of Landon Cahow, redzephyrdesign.com

If you’re an iPhone developer you’ll inevitably need to work with images at some point. It’s extremely easy to load and display images in a variety of formats such as PNG, JPEG, etc. That said, the easy route isn’t always the most efficient; taking the time to learn how the iPhone handles images (e.g., storing each pixel with Blue/Green/Red/Alpha-ordered octets instead of Red/Green/Blue) and how to use that knowledge to your advantage is definitely a worthwhile investment.

For example, the official Apple documentation suggests that you use the PNG image format for iPhone graphics and briefly mentions that Xcode does some sort of “optimization” on each .png file during a device build. What does this mean? Just how much more efficient is one of these mysterious “optimized” PNG files? Who knows! Apple doesn’t tell us.

Fortunately Jeff LaMarche took the time to write up an excellent, short, easy-to-read yet thorough explanation regarding the iPhone, image formats, and PNG optimization (link). Personally I feel like this should be required reading for all new iPhone developers (and I wish I had found the article sooner!).

Tutorial Featured on Mobile Orchard

by Clint on May 13, 2009

tutorial_-code-sharing-via-static-libraries-and-cross-project-references

I’m happy to announce that my “Xcode cross-project code sharing” tutorial has received over 1,000 hits and was recently “syndicated” by the excellent iPhone developer journal Mobile Orchard (they told me the tutorial received about 20,000 hits on their site–wow)! Mobile Orchard really is an excellent resource, especially in regards to their podcasts–I recommend it to any other iPhone developers.

Doxygen and C Preprocessor Directives

by Clint on March 4, 2009

I’ve been using a tool called Doxygen to document my Objective-C code; it’s comparable to javadoc in the Java world, but can be used with a much wider variety of languages (PHP, C#, and Java, to name a few). In a nutshell, you use a few special symbols when writing normal code comments and Doxygen can then generate HTML, class diagrams, etc., from your source code. (You can see a previous post of mine with some sample code for an example.)

One nice feature of Doxygen is that it can handle C preprocessor directives just like an actual build tool (e.g., gcc), and even generate documentation for them. For example, you might code your own “logging” macro that maps to the standard NSLog() function as follows:

/**
  Custom logging macro blah blah blah...
 */
#define MYLOG(...) NSLog(__VA_ARGS__)

Doxygen will actually include define statements like this in the HTML documentation it generates, including your code comments, as long as you haveĀ  ENABLE_PREPROCESSING=YES in your doxygen.config file.

While this is a great feature, you can run into trouble if you forget that conditional statements like #if will also be processed. For example, let’s say we only wanted to include some code if we’re building for the iPhone. Although it’s a bit contrived, we might rewrite the above macro as follows:

#if TARGET_OS_IPHONE

/**
  Custom logging macro blah blah blah...
 */
#define MYLOG(...) NSLog(__VA_ARGS__)

#endif

TARGET_OS_IPHONE is a standard variable that is automatically defined when you do regular builds in Xcode. But when you run Doxygen you’re not doing a “regular build” via Xcode and TARGET_OS_IPHONE isn’t defined. Assuming Doxygen’s preprocessor is enabled, the above #if statement would be false and the contained code (i.e., the MYLOG() definition) wouldn’t be included in your HTML documentation.

The trick, as I found recently, is to use the PREDEFINED setting in the doxygen.config file. This lets you define preprossor variables to mimic the Xcode build environment. Continuing the example, you would put the following in doxygen.config:

PREDEFINED = TARGET_OS_IPHONE=1

The result is that the TARGET_OS_IPHONE variable will not only be defined, but set to “1″, and MYLOG() will be processed by Doxygen.

Updated 8/18/09: Added info for 3GS (Thanks Jamey).

Erica Sadun recently shared a great post on Ars Technica showing how to determine specifically which model of iPhone or iPod Touch is being used, as opposed to the high-level “iPhone vs. iPod Touch” information made available via the UIDevice -model: method. As she points out, knowing the exact model can be pretty helpful as there are some significant differences between the different devices (e.g., the second-generation iPod Touch has speakers, while the first-generation model does not).

In a nutshell, you use a C function called sysctlbyname to get the hardware model (and if you’re not familiar with doing stuff in C like manually allocating and freeing memory, the code sample is really helpful). Here’s a snippet from the original post:

- (NSString *) platform
{
  size_t size;
  sysctlbyname("hw.machine", NULL, &size, NULL, 0);
  char *machine = malloc(size);
  sysctlbyname("hw.machine", machine, &size, NULL, 0);
  /*
  Possible values:
  "iPhone1,1" = iPhone 1G
  "iPhone1,2" = iPhone 3G
  "iPhone2,1" = iPhone 3GS
  "iPod1,1"   = iPod touch 1G
  "iPod2,1"   = iPod touch 2G
  */
  NSString *platform = [NSString stringWithCString:machine];

  free(machine);
  return platform;
}