Monday, October 20, 2008

Device vs. Simulator

The iPhone Simulator is a really cool piece of software. Although I do most of my development testing on an iPhone or iPod Touch, I really like having the option to run code when I don't have a device handy. It's a really cool piece of technology.

Sometimes, it can be downright annoying, though. Today, I hit an example of that. I'm working on a project that needs to run on both the Mac and the iPhone, and it does a fair bit of mucking around in the runtime. I've written programs using for both the Mac and the iPhone with no problems, but periodically would get e-mail from someone asking if I could make it work for the iPhone.

Well, it turns out *blush*... I must have never actually tested the code on an iPhone or iPod Touch, and only used this particular code in the simulator and on the Mac. You see, I have this line of code:


#import <objc/objc-runtime.h>


And that code works just fine and dandy for the Mac, and for the iPhone Simulator. But, guess what? obj/objc-runtime.h doesn't seem to exist in the iPhone SDK, so when you switch the SDK to the device and then compile, the build goes down in a blaze of gory (no, not glory, gory... it's ugly).

Fixing it was relatively trivial once I found the problem. The file objc/objc-runtime.h is a very simple header file. Here is what it looks like on the Mac:

#import <objc/runtime.h>
#import <objc/message.h>


That's it. And both of those files do exist for the device SDK. So, I simply replaced the one #import <objc/objc-runtime.h> statement with the two #import statements it contained, and voilá, it started working again. Mostly.

It compiled with no errors, but I got a whole bunch of warnings, all centered around the use of two methods it couldn't find: -className and +className. These methods do nothing more than return the name of the class, one is implemented as an instance method, the other as a class method. I have no idea why these two methods don't exist for the device SDK, but this was also easy enough to fix, since the class name is available through runtime calls.

I added the two methods, but wrapped the code in a pre-compiler conditional statement so it only gets used when compiling for the iPhone:

So, in the header file:

#if (TARGET_OS_IPHONE)
- (NSString *)className;
+ (NSString *)className;
#endif


Currently, this resides on the class where I needed it, but I'm going to move it into a category on NSObject. The implementation of these two methods is nearly as short:


#if (TARGET_OS_IPHONE)
- (NSString *)className
{
return [NSString stringWithUTF8String:class_getName([self class])];
}
+ (NSString *)className
{
return [NSString stringWithUTF8String:class_getName(self)];
}
#endif


And that's all for today, I'm going to bed.

No comments:

Post a Comment