Posted on July 6, 2010 by John Muchow in Xcode

If you’ve installed Xcode 3.2.3 you quickly became aware that the only SDK’s packaged with this version are 4.0 and 3.2. Until 4.x has widespread adoption, chances are you’ll want your applications to run on earlier versions of the iPhone OS (iOS) SDK. You can accomplish this feat through two configuration options within Xcode, the Base SDK and the iPhone OS Deployment Target.

Base SDK

The Base SDK is the version of SDK that will be used when compiling your application – the compiler will use the headers and libraries of this specific SDK. For example, in the image below notice that there are only two choices for the Base SDK for both the device and simulator, versions 3.2 and 4.0.

However, we have an issue here, if you build an application with the latest SDK and deploy on a device with an earlier OS, chances are your application will crash if you reference any code in a 4.x API while running the application on a 3.x device. Also, the 3.2 SDK is for the iPad only, so this isn’t an option when deploying to an iPhone or iPod touch.

iPhone OS Deployment Target

To specify which OS version is the minimum that your application will support, you set the deployment target. Your application will then run on this minimum OS as well as all later versions.

This is all well and good, however, the obvious question is how to deploy on an earlier OS version yet take advantage of features for those devices that are running a later OS?

Check for Feature Availability Not OS Version

When targeting an earlier OS as mentioned above, yet you want to take advantage of features of a later OS for devices that support it, you can use the method respondsToSelector to check if the receiver implements or inherits a method that can respond to a specified message. This approach follows Apple’s recommendation to check for availability of features versus a specific OS version.

In the example below the code will check if the object returned by [UIDevice currentDevice] will respond to the selector shown, if so, you can write relevant multi-tasking code:

if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)])
{
  // Multi-tasking code for supported devices
}
else
{
  // Devices without multi-tasking support
}

Another time when that you may choose to use respondsToSelector is for cases when the implementation of the same API has changed with a later OS version. I ran into this particular case when writing code for displaying movies using the MPMoviePlayerController. In the 4.x SDK the notifications have changed slightly – in 2.0 to 3.1 MPMoviePlayerContentPreloadDidFinishNotification was the notification you would use to receive notice that a movie was ready to play. With 3.2 (iPad) and later, MPMoviePlayerContentPreloadDidFinishNotification has been deprecated and MPMoviePlayerLoadStateDidChangeNotification has taken its place.

The code example below shows how you may go about using respondsToSelector to figure out which notification you should request based on the whether or not the movie player can return information about its load state:

MPMoviePlayerController *mp =
   [[MPMoviePlayerController alloc] initWithContentURL:movieURL];

// This method is available on 3.2 and greater...
 if ([mp respondsToSelector:@selector(loadState)])
{
  // Register to receive notification when load state changed
  // (check for playable, stalled...)
  [[NSNotificationCenter defaultCenter] addObserver:self
                       selector:@selector(moviePlayerLoadStateChanged:)
                       name:MPMoviePlayerLoadStateDidChangeNotification
                       object:nil];

}
else
{
  // Register to receive a notification when the movie is ready to play.
  [[NSNotificationCenter defaultCenter] addObserver:self
                         selector:@selector(moviePreloadDidFinish:)
                         name:MPMoviePlayerContentPreloadDidFinishNotification
                         object:nil];

}
Check for Function Availability

Beyond working with objects, if you need to check for the availability of a specific function, you do so by comparing the function to NULL. In the example below I check for a function related to creating a PDF-based graphics context (available in 3.2 and later).

if (UIGraphicsBeginPDFContextToFile != NULL)
{
  // The function is available
}
Testing Across OS Versions

Unfortunately, with the upgrade to the latest Xcode (3.2.3) there are no simulators for 3.1.x and earlier OS versions. Although it has always been recommended to test your apps on device, at this point it becomes a necessity.

Advertisements