Base SDK, Deployment Target, Weak linking and import

With the new release of Xcode for iOS 4, I was disappointed to find out that it’s not possible to select versions of the iPhone SDK prior to 3.2 from the usual build drop-down box. So I decided to take the annoying opportunity to find out more about how to create applications that use a certain level of features (eg, iOS 4) while still running gracefully on previous versions of the operating system (eg, iPhone OS 3.0). I have wanted to get to grips with this for a long time. Given that you need to tweak these settings more consciously with Xcode 3.2.3, I suppose now is the time.
You can set the highest version of the OS you want to access through the Base SDK compiler option (careful: despite the debatable name choice, the Base SDK is actually the maximum version you intend to support). Then you can set the Deployment Target option to let the application run on previous versions of the OS, down to the one you specify in this setting.

Setting Meaning GCC Compiler Option
SDKROOT (Base SDK) The maximum version supported -isysroot
IPHONEOS_DEPLOYMENT_TARGET (Deployment Target) The minimum version supported -miphoneos-version-min

These properties can be configured by right-clicking on your Xcode project and selecting Get Info. The Build tab contains both, the former under the Architectures section, the latter under Deployment.

Writing code for a multi-OS app

Once you’ve configured your project to run on a minimum OS and support features of a maximum OS, you have one problem: how does your code behave in order to support new features of the maximum OS only where they are available?
Two cases: (1) the framework (eg, UIKit) already existed in previous supported versions, but some of the features are new to the Base SDK, (2) the framework (eg, iAd) is new to the Base SDK. In the former case, nothing to do, just follow the general development guidelines. In the latter, you need to weak-link the library, which means that the compiler will link it if it finds it, or just leave it if it doesn’t, without raising any major issues.

Existing frameworks

Add the framework to your project as usual, no extra work needed. When you want to use features of the framework that have been introduced in the latest releases, you should write conditional runtime code that verifies that the class or method you’re looking for actually exist before you instantiate or invoke them. You can use the NSClassFromString function that takes a string for the class name and will return nil if the class doesn’t exist, or the method respondsToSelector that tells you whether an object has the specified method (there is also a static version instancesRespondToSelector that you can invoke on a class reference directly).
If you’re running code in iOS 4 that will support iPhone OS 3.1 but no earlier, then you could use weak import. It is a new feature of Objective C whereby code like this [MyTestClass class] will return nil instead of crashing the application. You need to make your code compile first (so the class header must be available at compile time), but at runtime it doesn’t matter whether the class definition is not found: your code will just get nil back and can react accordingly.

New frameworks

If the framework you plan to use was introduced in the release you are targeting, you will still have to follow all of the tips of the previous section, but you will have the added issue that the app will crash on older version of the iPhone OS where the framework is not available. The solution to this is to weak-link the framework. The app will look for it on the device, and if not found it will run anyway… you will have made sure that it can work with conditional runtime checks ;-)
In order to weak link a framework, select your target in Xcode, right-click and Get Info. Under the General tab there’s a Linked Frameworks section. The Type column value can be changed from Required to Weak, which will make the corresponding framework weakly linked to your application.

You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

3 Comments »

 
  • Mars says:

    I have tried running my app with the EventKit required and weak linked to my target to no avail. The first scenario crashes the app onload and says couldnt load dyld image not found, data formatters unavailable, cannot call into the loader, it is locked. The second scenario just loads up to a white screen on the simulator. I know its not a coding problem for 2 reasons:

    1) the app works fine even in 3.2, if i just take out the #import EventKit line and the 10 lines that actually call it, which are the same lines that call it for the iPhone version which works fine (this is a universal app).

    2) the way the app is set up, its a tab controller with 2 view controllers. The eventkit class that i use doesnt get called until i load the 2nd tab of the tabBarController, and even then only when i click a button in that tabVC. The #import Eventkit line is only in that 2nd tabVC. So there is no reason for the app not to load properly.

    Any other ideas would be greatly appreciated.

  • Clint says:

    Wow, this is a huge help for a wildly subtle issue.

    I updated to SDK4/Xcode3.2.3 and couldn’t find this answer anywhere. I was on the verge of putting up a redundant Stack Overflow question until I came across this.

    Thanks for the write-up!

  • FabrizioC says:

    Great!
    The last section (“New framework”) is what I looking for, but the post is all useful.
    Thanks

 

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

*