Checking device or system version.

February 3rd, 2014 posted in Apps Developement Objective-C

Sometimes you need to check the system version, because some a newer version of the SDK adds new methods or worse deprecates one in favor of an new one. I often see example like this one:

if ([[[UIDevice currentDevice]systemVersion]floatValue]<5.0) {
	[self presentModalViewController:errorView animated:YES];
} else {
	[self presentViewController:errorView animated:YES completion:nil];
}

In this example you’ll see that the system version is casted to a float and checked where it is lower than 5.0.

This might look like a great check, but it is not! In the example you are assuming that all device system versions will be the same, which they are note. For example the Apple TV, it is also running iOS and currently running version 6 of it operating system, which based on iOS 7. So a device check of the system version will fail for an app running on both system. (lets just assume that you could build app for the Apple tv for the sake of this example).

The solution is very simple, just check if the new method is available.

if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]) {
	[self presentViewController:errorView animated:YES completion:nil];
} else {
	[self presentModalViewController:errorView animated:YES];
}

No this code is more future proof then the pervious one, because you are just checking wether the method is available.

If you want to use a class which is not available in a previous version of the SDK you can also easily do a check if the class method returns a value:

if ([MKMapCamera class]) {
	// Go ahead and use the class.
}

When there is option to check the class or method existence you should check the foundation version. The foundation version is the version of the underlying API (Foundation/SDK version). Apple gives a great example for this in there iOS 7 transition guide:

if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
 	 // Load resources for iOS 6.1 or earlier
} else {
  	// Load resources for iOS 7 or later
}

This is the only correct way of checking the system version, well system version is not correct in this context. You really look to the API (Foundation/SDK) version.

Device modifiers

No lets talk about different devices. For a universal App you will need to support 3,5”, 4” and iPad devices.

Apple made it very easy for a developer to load device specific resources, they call this device modifiers. There are now to known device modifiers: ~ipad and ~iphone. They work almost the same as the @2x modifier for images.

Lets look at the following example you will find on many answer on stack overflow.

MyViewController *viewController = nil;
if (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone) {
	viewController = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];
 
} else {
	viewController= [[MyViewController alloc] initWithNibName:@“MyViewController_ipad" bundle:nil];
}

You see the conditional loading of the view (NIB) based on the device idiom, this can replaced by one line. Just be sure that the file names are correct. The iPhone version of the NIB can be MyViewController.xib and the iPad version should then be MyViewController~ipad.xib. Then just create your view controller like you normally would.

MyViewController *viewController =  [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];

This will also work for storyboards and images.

Your app should also support both the 4,5” and 4” iOS devices. This can easily be done by using autolayout to adjust you UI to match the height of the screen. But even without autolayout can make you UI grow to fill the screen. Just be sure that you set the correct auto resize mask in interface builder.

Utilizing these techniques will save you a lot of work and make debugger you app easier.