- Creating New Projects
- Building Hello World the Template Way
- Using the Simulator
- The Minimalist Hello World
- Converting Interface Builder Files to Their Objective-C Equivalents
- Using the Debugger
- Memory Management
- Recipe: Using Instruments to Detect Leaks
- Recipe: Using Instruments to Monitor Cached Object Allocations
- Analyzing Your Code
- Building for the iOS Device
- Detecting Simulator Builds with Compile-Time Checks
- Performing Runtime Compatibility Checks
- Pragma Marks
- Preparing for Distribution
- Over-the-Air Ad Hoc Distribution
- Submitting to the App Store
Performing Runtime Compatibility Checks
There is a real and measurable adoption lag among iOS device users. To sell your application to the greatest number of customers, do not build for any SDK higher than your lowest desired customer. Use common sense when picking that SDK. You may find it best to support the most recent firmware dot release that lags a few weeks or months behind the latest iOS update, or you may want to extend support to all versions of the current iOS firmware.
The hardest decisions come when iOS moves forward to a new version. That’s when the adoption rate slows down the most. The 3.x/4.x overlap lasted for some time before developers gained confidence in moving forward to 4.x-only releases. iOS 5 and its successors continue that challenge.
To build for a range of possible deployment targets, set your Base SDK to the highest version of the OS you want to target—usually the current SDK release. Set your iOS deployment target to the lowest OS version you intend to build for.
When compiling to a deployment target that is earlier than your base SDK, you’ll need to perform runtime checks for any classes or API calls that might not yet have been introduced to a given firmware platform. For example, an iOS 5-introduced API call will not be available on an iOS 4.2 installation. The following tests allow you to check at runtime for classes and methods that may or may not be available depending on the deployment platform:
- Check platform geometry—Introduced in iOS 3.2, the idiom check lets you determine if your code is running on an iPhone-like unit (iPhone, iPod touch) or on an iPad. I have not included extensions here to see whether the check itself is implemented simply because I cannot recommend deploying to pre-3.2 platforms anymore. As of the Summer of 2011, 3.x platforms made up only about 5% of all iOS installations. Pre-3.2 installs were a vanishingly small percentage of that.
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) . . .
- Check deployment platform—Use the model property of the UIDevice class to determine whether the unit is running on an @"iPhone" or @"iPad". More nuanced platform detection is discussed in Chapter 14, “Devices Capabilities.”
if ([[UIDevice currentDevice].model isEqualToString:@"iPad"]) . . .
- Check system prefix—It’s not the best way to approach coding (checking classes and instances directly is far more reliable), but you can check the current system version directly.
if ([[[UIDevice currentDevice] systemVersion] hasPrefix:@"5."]) . . .
- Check for properties using key-value coding—You can determine whether an object offers a value for a given key within the current scope, which allows you to test for properties.
UILabel *label = (UILabel *)[cell valueForKey:@"textLabel"]; if (label) [label setText:celltext];
- Check for class existence—If a class may not exist on a given deployment target, use NSClassFromString() to test whether the class can be produced from its name. Pass it an NSString, such as the following:
if (NSClassFromString(@"NSAttributedString")) . . .
- Check for function existence—You can test for functions before attempting to call them.
if(&UIGraphicsBeginImageContextWithOptions != NULL) . . .
- Check for selector compliance—You can test objects to see whether they respond to specific selectors. When newer APIs are supported, objects will report that they respond to those selectors, letting you call them without crashing the program. You may generate compile-time warnings about unimplemented selectors unless you use workarounds such as performSelector:withObject:. If you really want to go hard core, you can build NSInvocation instances directly, as discussed in Chapter 3.
if ([cell respondsToSelector:@selector(selectorName:)]) . . .