Cocoa code branching per release?

How do I branch Cocoa code to use newer classes if available but still work on older OS releases?

I have a 10.4 only Cocoa application. It uses some private API for something and when running that feature in Mac OS X 10.5 the application crashes. The good news is that there is now a public API for this thing. What I’d like to do is use a little if block (something like if (NSClassFromString(@"NSNewCoolClass") == nil)) and continue to use my hack in 10.4 and the new official stuff for 10.5.

What I’m a little unsure of is how I can do this. If I write code with NSNewCoolClass the compiler barfs cause it doesn’t know what it is (I’m still linking against MacOSX10.4u.sdk). My understanding is if I link against the 10.5 sdk it won’t work on 10.4 (which is a must for me). So what should I do?

Posted on: June 29, 2007 – 11:21 pm

5 Comments

  1. Compile your main code for 10.4.

    Put 10.5 specific code into a loadable bundle…

  2. You’re sort of right that you have to use the “if” block to interact with a 10.y-only class from code that might run on 10.x (where y = x + 1; this has been true since Jaguar). You actually need to use NSClassFromString to refer to the class itself as well:

    Class MyNSNewCoolClass = NSClassFromString(@”NSNewCoolClass”); if (MyNSNewCoolClass != nil) { id coolInstance = [[MyNSNewCoolClass alloc] init]; }

    Jonathan is right to suggest using a separate bundle; this is required if you want to subclass 10.y classes.

    There’s one correction I’d like to make though. When you build against an SDK, that SDK defines which version of the Mac OS X APIs you’re building against. There’s a separate build setting - the Mac OS X Deployment Target - that defines the earliest version of Mac OS X that you want your code to run on. This causes any global symbols (functions, global variables like notification names, etc. - sadly not classes though) introduced with a later version of Mac OS X to be weak-linked and automatically nil when run on an earlier OS.

    Thus you can write an application that runs on Mac OS X 10.3 but uses 10.4 API when present by doing the following:

    (1) Building the application against the Mac OS X 10.4u SDK, because that’s the version of the API you want to use.

    (2) Setting the application’s Mac OS X Deployment Target to 10.3, because that’s the minimum system you want it to run on.

    (3) Checking that any functions or global symbols introduced in 10.4 are nil before using them.

    (4) Using NSClassFromString as above to interact with classes introduced in 10.4.

    (5) Using a separate bundle to subclass 10.4 classes.

    Hope this helps!

  3. @Chris Thanks so much for the help. One more question: I have a Tiger hard drive and a Leopard hard drive for my Mac Pro. Could I use Xcode 2.4 on Tiger and point it to the sdk living on the Leopard HD to build against that SDK? I ask cause I’m not ready to live in 10.5 yet. My NIBs (cause they use some open source IB Pallets that haven’t been upgraded to IB 3 yet, and who even knows how ready IB3 is for such things) don’t open in IB3 so it’d be really awkward to do all the code in Xcode and reboot to 10.4 just to edit the NIBs.

    Old IB used to be in the seeds. I don’t know where it went. :-(

    Thanks again.

  4. I doubt that would work; a 10.y SDK is free to use features from 10.y itself (for example, changes to the compiler, such as the introduction of a deprecation attribute in GCC 4 with Tiger) which may not be available on 10.x.

  5. Check the release notes and connect.apple.com for info on a Tiger compatible IB version in 10.5. You should be pleasantly surprised. :)

Post a Comment | Comment RSS feed