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|
||The maximum version supported||
||The minimum version supported||
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.
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.
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.