How to check osx version at compile time? [duplicate] - swift

I want to check if the iOS version of the device is greater than 3.1.3
I tried things like:
[[UIDevice currentDevice].systemVersion floatValue]
but it does not work, I just want a:
if (version > 3.1.3) { }
How can I achieve this?

/*
* System Versioning Preprocessor Macros
*/
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
/*
* Usage
*/
if (SYSTEM_VERSION_LESS_THAN(#"4.0")) {
...
}
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"3.1.1")) {
...
}

The quick answer …
As of Swift 2.0, you can use #available in an if or guard to protect code that should only be run on certain systems.
if #available(iOS 9, *) {}
In Objective-C, you need to check the system version and perform a comparison.
[[NSProcessInfo processInfo] operatingSystemVersion] in iOS 8 and above.
As of Xcode 9:
if (#available(iOS 9, *)) {}
The full answer …
In Objective-C, and Swift in rare cases, it's better to avoid relying on the operating system version as an indication of device or OS capabilities. There is usually a more reliable method of checking whether a particular feature or class is available.
Checking for the presence of APIs:
For example, you can check if UIPopoverController is available on the current device using NSClassFromString:
if (NSClassFromString(#"UIPopoverController")) {
// Do something
}
For weakly linked classes, it is safe to message the class, directly. Notably, this works for frameworks that aren't explicitly linked as "Required". For missing classes, the expression evaluates to nil, failing the condition:
if ([LAContext class]) {
// Do something
}
Some classes, like CLLocationManager and UIDevice, provide methods to check device capabilities:
if ([CLLocationManager headingAvailable]) {
// Do something
}
Checking for the presence of symbols:
Very occasionally, you must check for the presence of a constant. This came up in iOS 8 with the introduction of UIApplicationOpenSettingsURLString, used to load Settings app via -openURL:. The value didn't exist prior to iOS 8. Passing nil to this API will crash, so you must take care to verify the existence of the constant first:
if (&UIApplicationOpenSettingsURLString != NULL) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}
Comparing against the operating system version:
Let's assume you're faced with the relatively rare need to check the operating system version. For projects targeting iOS 8 and above, NSProcessInfo includes a method for performing version comparisons with less chance of error:
- (BOOL)isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion)version
Projects targeting older systems can use systemVersion on UIDevice. Apple uses it in their GLSprite sample code.
// A system version of 3.1 or greater is required to use CADisplayLink. The NSTimer
// class is used as fallback when it isn't available.
NSString *reqSysVer = #"3.1";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending) {
displayLinkSupported = TRUE;
}
If for whatever reason you decide that systemVersion is what you want, make sure to treat it as an string or you risk truncating the patch revision number (eg. 3.1.2 -> 3.1).

As suggested by the official Apple docs: you can use the NSFoundationVersionNumber, from the NSObjCRuntime.h header file.
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
// here you go with iOS 7
}

Starting Xcode 9, in Objective-C:
if (#available(iOS 11, *)) {
// iOS 11 (or newer) ObjC code
} else {
// iOS 10 or older code
}
Starting Xcode 7, in Swift:
if #available(iOS 11, *) {
// iOS 11 (or newer) Swift code
} else {
// iOS 10 or older code
}
For the version, you can specify the MAJOR, the MINOR or the PATCH (see http://semver.org/ for definitions). Examples:
iOS 11 and iOS 11.0 are the same minimal version
iOS 10, iOS 10.3, iOS 10.3.1 are different minimal versions
You can input values for any of those systems:
iOS, macOS, watchOS, tvOS
Real case example taken from one of my pods:
if #available(iOS 10.0, tvOS 10.0, *) {
// iOS 10+ and tvOS 10+ Swift code
} else {
// iOS 9 and tvOS 9 older code
}
documentation

Try:
NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare: #"3.1.3" options: NSNumericSearch];
if (order == NSOrderedSame || order == NSOrderedDescending) {
// OS version >= 3.1.3
} else {
// OS version < 3.1.3
}

Preferred Approach
In Swift 2.0 Apple added availability checking using a far more convenient syntax (Read more here). Now you can check the OS version with a cleaner syntax:
if #available(iOS 9, *) {
// Then we are on iOS 9
} else {
// iOS 8 or earlier
}
This is the preferred over checking respondsToSelector etc (What's New In Swift). Now the compiler will always warn you if you aren't guarding your code properly.
Pre Swift 2.0
New in iOS 8 is NSProcessInfo allowing for better semantic versioning checks.
Deploying on iOS 8 and greater
For minimum deployment targets of iOS 8.0 or above, use NSProcessInfo
operatingSystemVersion or isOperatingSystemAtLeastVersion.
This would yield the following:
let minimumVersion = NSOperatingSystemVersion(majorVersion: 8, minorVersion: 1, patchVersion: 2)
if NSProcessInfo().isOperatingSystemAtLeastVersion(minimumVersion) {
//current version is >= (8.1.2)
} else {
//current version is < (8.1.2)
}
Deploying on iOS 7
For minimum deployment targets of iOS 7.1 or below, use compare with
NSStringCompareOptions.NumericSearch on UIDevice systemVersion.
This would yield:
let minimumVersionString = "3.1.3"
let versionComparison = UIDevice.currentDevice().systemVersion.compare(minimumVersionString, options: .NumericSearch)
switch versionComparison {
case .OrderedSame, .OrderedDescending:
//current version is >= (3.1.3)
break
case .OrderedAscending:
//current version is < (3.1.3)
fallthrough
default:
break;
}
More reading at NSHipster.

I always keep those in my Constants.h file:
#define IS_IPHONE5 (([[UIScreen mainScreen] bounds].size.height-568)?NO:YES)
#define IS_OS_5_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 5.0)
#define IS_OS_6_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0)
#define IS_OS_7_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)

+(BOOL)doesSystemVersionMeetRequirement:(NSString *)minRequirement{
// eg NSString *reqSysVer = #"4.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:minRequirement options:NSNumericSearch] != NSOrderedAscending)
{
return YES;
}else{
return NO;
}
}

With Version class that is contained in nv-ios-version project (Apache License, Version 2.0), it is easy to get and compare iOS version. An example code below dumps the iOS version and checks whether the version is greater than or equal to 6.0.
// Get the system version of iOS at runtime.
NSString *versionString = [[UIDevice currentDevice] systemVersion];
// Convert the version string to a Version instance.
Version *version = [Version versionWithString:versionString];
// Dump the major, minor and micro version numbers.
NSLog(#"version = [%d, %d, %d]",
version.major, version.minor, version.micro);
// Check whether the version is greater than or equal to 6.0.
if ([version isGreaterThanOrEqualToMajor:6 minor:0])
{
// The iOS version is greater than or equal to 6.0.
}
// Another way to check whether iOS version is
// greater than or equal to 6.0.
if (6 <= version.major)
{
// The iOS version is greater than or equal to 6.0.
}
Project Page: nv-ios-version
TakahikoKawasaki/nv-ios-version
Blog: Get and compare iOS version at runtime with Version class
Get and compare iOS version at runtime with Version class

I know this is an old question, but someone should have mentioned the compile-time macros in Availability.h. All of the other methods here are runtime solutions, and will not work in a header file, class category, or ivar definition.
For these situations, use
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0 && defined(__IPHONE_14_0)
// iOS 14+ code here
#else
// Pre iOS 14 code here
#endif
h/t this answer

if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
// Your code here
}
Where of course, NSFoundationVersionNumber_iOS_6_1 must be changed to by applicable for the iOS version you want to check. What I have now written will probably be used a lot when testing if a device is running iOS7 or a previous version.

New way to check the system version using the swift Forget [[UIDevice currentDevice] systemVersion] and NSFoundationVersionNumber.
We can use NSProcessInfo -isOperatingSystemAtLeastVersion
import Foundation
let yosemite = NSOperatingSystemVersion(majorVersion: 10, minorVersion: 10, patchVersion: 0)
NSProcessInfo().isOperatingSystemAtLeastVersion(yosemite) // false

a bit late to the party but in light of iOS 8.0 out there this might be relevant:
if you can avoid using
[[UIDevice currentDevice] systemVersion]
Instead check for existence of of a method/class/whatever else.
if ([self.yourClassInstance respondsToSelector:#selector(<yourMethod>)])
{
//do stuff
}
I found it to be useful for location manager where I have to call requestWhenInUseAuthorization for iOS 8.0 but the method is not available for iOS < 8

UIDevice+IOSVersion.h
#interface UIDevice (IOSVersion)
+ (BOOL)isCurrentIOSVersionEqualToVersion:(NSString *)iOSVersion;
+ (BOOL)isCurrentIOSVersionGreaterThanVersion:(NSString *)iOSVersion;
+ (BOOL)isCurrentIOSVersionGreaterThanOrEqualToVersion:(NSString *)iOSVersion;
+ (BOOL)isCurrentIOSVersionLessThanVersion:(NSString *)iOSVersion;
+ (BOOL)isCurrentIOSVersionLessThanOrEqualToVersion:(NSString *)iOSVersion
#end
UIDevice+IOSVersion.m
#import "UIDevice+IOSVersion.h"
#implementation UIDevice (IOSVersion)
+ (BOOL)isCurrentIOSVersionEqualToVersion:(NSString *)iOSVersion
{
return [[[UIDevice currentDevice] systemVersion] compare:iOSVersion options:NSNumericSearch] == NSOrderedSame;
}
+ (BOOL)isCurrentIOSVersionGreaterThanVersion:(NSString *)iOSVersion
{
return [[[UIDevice currentDevice] systemVersion] compare:iOSVersion options:NSNumericSearch] == NSOrderedDescending;
}
+ (BOOL)isCurrentIOSVersionGreaterThanOrEqualToVersion:(NSString *)iOSVersion
{
return [[[UIDevice currentDevice] systemVersion] compare:iOSVersion options:NSNumericSearch] != NSOrderedAscending;
}
+ (BOOL)isCurrentIOSVersionLessThanVersion:(NSString *)iOSVersion
{
return [[[UIDevice currentDevice] systemVersion] compare:iOSVersion options:NSNumericSearch] == NSOrderedAscending;
}
+ (BOOL)isCurrentIOSVersionLessThanOrEqualToVersion:(NSString *)iOSVersion
{
return [[[UIDevice currentDevice] systemVersion] compare:iOSVersion options:NSNumericSearch] != NSOrderedDescending;
}
#end

Just for retrieving the OS version string value:
[[UIDevice currentDevice] systemVersion]

In general it's better to ask if an object can perform a given selector, rather than checking a version number to decide if it must be present.
When this is not an option, you do need to be a bit careful here because [#"5.0" compare:#"5" options:NSNumericSearch] returns NSOrderedDescending which might well not be intended at all; I might expect NSOrderedSame here. This is at least a theoretical concern, one that is worth defending against in my opinion.
Also worth considering is the possibility of a bad version input which can not reasonably be compared to. Apple supplies the three predefined constants NSOrderedAscending, NSOrderedSame and NSOrderedDescending but I can think of a use for some thing called NSOrderedUnordered in the event I can't compare two things and I want to return a value indicating this.
What's more, it's not impossible that Apple will some day expand their three predefined constants to allow a variety of return values, making a comparison != NSOrderedAscending unwise.
With this said, consider the following code.
typedef enum {kSKOrderedNotOrdered = -2, kSKOrderedAscending = -1, kSKOrderedSame = 0, kSKOrderedDescending = 1} SKComparisonResult;
#interface SKComparator : NSObject
+ (SKComparisonResult)comparePointSeparatedVersionNumber:(NSString *)vOne withPointSeparatedVersionNumber:(NSString *)vTwo;
#end
#implementation SKComparator
+ (SKComparisonResult)comparePointSeparatedVersionNumber:(NSString *)vOne withPointSeparatedVersionNumber:(NSString *)vTwo {
if (!vOne || !vTwo || [vOne length] < 1 || [vTwo length] < 1 || [vOne rangeOfString:#".."].location != NSNotFound ||
[vTwo rangeOfString:#".."].location != NSNotFound) {
return SKOrderedNotOrdered;
}
NSCharacterSet *numericalCharSet = [NSCharacterSet characterSetWithCharactersInString:#".0123456789"];
NSString *vOneTrimmed = [vOne stringByTrimmingCharactersInSet:numericalCharSet];
NSString *vTwoTrimmed = [vTwo stringByTrimmingCharactersInSet:numericalCharSet];
if ([vOneTrimmed length] > 0 || [vTwoTrimmed length] > 0) {
return SKOrderedNotOrdered;
}
NSArray *vOneArray = [vOne componentsSeparatedByString:#"."];
NSArray *vTwoArray = [vTwo componentsSeparatedByString:#"."];
for (NSUInteger i = 0; i < MIN([vOneArray count], [vTwoArray count]); i++) {
NSInteger vOneInt = [[vOneArray objectAtIndex:i] intValue];
NSInteger vTwoInt = [[vTwoArray objectAtIndex:i] intValue];
if (vOneInt > vTwoInt) {
return kSKOrderedDescending;
} else if (vOneInt < vTwoInt) {
return kSKOrderedAscending;
}
}
if ([vOneArray count] > [vTwoArray count]) {
for (NSUInteger i = [vTwoArray count]; i < [vOneArray count]; i++) {
if ([[vOneArray objectAtIndex:i] intValue] > 0) {
return kSKOrderedDescending;
}
}
} else if ([vOneArray count] < [vTwoArray count]) {
for (NSUInteger i = [vOneArray count]; i < [vTwoArray count]; i++) {
if ([[vTwoArray objectAtIndex:i] intValue] > 0) {
return kSKOrderedAscending;
}
}
}
return kSKOrderedSame;
}
#end

#define _kisiOS7 ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
if (_kisiOS7) {
NSLog(#"iOS7 or greater")
}
else {
NSLog(#"Less than iOS7");
}

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
Then add a if condition as follows:-
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"10.0")) {
//Your code
}

There are version like 7.0 or 6.0.3, so we can simply convert version into numerics to compare. if version is like 7.0, simply append another ".0" to it and then take its numeric value.
int version;
NSString* iosVersion=[[UIDevice currentDevice] systemVersion];
NSArray* components=[iosVersion componentsSeparatedByString:#"."];
if ([components count]==2) {
iosVersion=[NSString stringWithFormat:#"%#.0",iosVersion];
}
iosVersion=[iosVersion stringByReplacingOccurrencesOfString:#"." withString:#""];
version=[iosVersion integerValue];
For 6.0.0
if (version==600) {
// Do something
}
for 7.0
if (version==700) {
// Do something
}

Try the below code:
NSString *versionString = [[UIDevice currentDevice] systemVersion];

As a variation of yasimturks solution, I defined one function and a few enum values instead of five macros. I find it more elegant, but that's a matter of taste.
Usage:
if (systemVersion(LessThan, #"5.0")) ...
.h file:
typedef enum {
LessThan,
LessOrEqual,
Equal,
GreaterOrEqual,
GreaterThan,
NotEqual
} Comparison;
BOOL systemVersion(Comparison test, NSString* version);
.m file:
BOOL systemVersion(Comparison test, NSString* version) {
NSComparisonResult result = [[[UIDevice currentDevice] systemVersion] compare: version options: NSNumericSearch];
switch (test) {
case LessThan: return result == NSOrderedAscending;
case LessOrEqual: return result != NSOrderedDescending;
case Equal: return result == NSOrderedSame;
case GreaterOrEqual: return result != NSOrderedAscending;
case GreaterThan: return result == NSOrderedDescending;
case NotEqual: return result != NSOrderedSame;
}
}
You should add your app's prefix to the names, especially to the Comparison type.

Using the refered recommended way... if there is no definition in the header files, you can always get the versión printing it on console with a device of the desired IOS versión.
- (BOOL) isIOS8OrAbove{
float version802 = 1140.109985;
float version8= 1139.100000; // there is no def like NSFoundationVersionNumber_iOS_7_1 for ios 8 yet?
NSLog(#"la version actual es [%f]", NSFoundationVersionNumber);
if (NSFoundationVersionNumber >= version8){
return true;
}
return false;
}

Solution for checking iOS version in Swift
switch (UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch)) {
case .OrderedAscending:
println("iOS < 8.0")
case .OrderedSame, .OrderedDescending:
println("iOS >= 8.0")
}
Con of this solution: it is simply bad practice to check against OS version numbers, whichever way you do it. One should never hard code dependencies in this way, always check for features, capabilities or the existence of a class. Consider this; Apple may release a backwards compatible version of a class, if they did then the code you suggest would never use it as your logic looks for an OS version number and NOT the existence of the class.
(Source of this information)
Solution for checking the class existence in Swift
if (objc_getClass("UIAlertController") == nil) {
// iOS 7
} else {
// iOS 8+
}
Do not use if (NSClassFromString("UIAlertController") == nil) because it works correctly on the iOS simulator using iOS 7.1 and 8.2, but if you test on a real device using iOS 7.1, you will unfortunately notice that you will never pass through the else part of the code snippet.

#define IsIOS8 (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1)

A more generic version in Obj-C++ 11 (you could probably replace some of this stuff with the NSString/C functions, but this is less verbose. This gives you two mechanisms. splitSystemVersion gives you an array of all the parts which is useful if you just want to switch on the major version (e.g. switch([self splitSystemVersion][0]) {case 4: break; case 5: break; }).
#include <boost/lexical_cast.hpp>
- (std::vector<int>) splitSystemVersion {
std::string version = [[[UIDevice currentDevice] systemVersion] UTF8String];
std::vector<int> versions;
auto i = version.begin();
while (i != version.end()) {
auto nextIllegalChar = std::find_if(i, version.end(), [] (char c) -> bool { return !isdigit(c); } );
std::string versionPart(i, nextIllegalChar);
i = std::find_if(nextIllegalChar, version.end(), isdigit);
versions.push_back(boost::lexical_cast<int>(versionPart));
}
return versions;
}
/** Losslessly parse system version into a number
* #return <0>: the version as a number,
* #return <1>: how many numeric parts went into the composed number. e.g.
* X.Y.Z = 3. You need this to know how to compare again <0>
*/
- (std::tuple<int, int>) parseSystemVersion {
std::string version = [[[UIDevice currentDevice] systemVersion] UTF8String];
int versionAsNumber = 0;
int nParts = 0;
auto i = version.begin();
while (i != version.end()) {
auto nextIllegalChar = std::find_if(i, version.end(), [] (char c) -> bool { return !isdigit(c); } );
std::string versionPart(i, nextIllegalChar);
i = std::find_if(nextIllegalChar, version.end(), isdigit);
int part = (boost::lexical_cast<int>(versionPart));
versionAsNumber = versionAsNumber * 100 + part;
nParts ++;
}
return {versionAsNumber, nParts};
}
/** Assume that the system version will not go beyond X.Y.Z.W format.
* #return The version string.
*/
- (int) parseSystemVersionAlt {
std::string version = [[[UIDevice currentDevice] systemVersion] UTF8String];
int versionAsNumber = 0;
int nParts = 0;
auto i = version.begin();
while (i != version.end() && nParts < 4) {
auto nextIllegalChar = std::find_if(i, version.end(), [] (char c) -> bool { return !isdigit(c); } );
std::string versionPart(i, nextIllegalChar);
i = std::find_if(nextIllegalChar, version.end(), isdigit);
int part = (boost::lexical_cast<int>(versionPart));
versionAsNumber = versionAsNumber * 100 + part;
nParts ++;
}
// don't forget to pad as systemVersion may have less parts (i.e. X.Y).
for (; nParts < 4; nParts++) {
versionAsNumber *= 100;
}
return versionAsNumber;
}

Try this
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
// do some work
}

float deviceOSVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
float versionToBeCompared = 3.1.3; //(For Example in your case)
if(deviceOSVersion < versionToBeCompared)
//Do whatever you need to do. Device version is lesser than 3.1.3(in your case)
else
//Device version should be either equal to the version you specified or above

Swift example that actually works:
switch UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch) {
case .OrderedSame, .OrderedDescending:
println("iOS >= 8.0")
case .OrderedAscending:
println("iOS < 8.0")
}
Don't use NSProcessInfo cause it doesn't work under 8.0, so its pretty much useless until 2016

Here is a swift version:
struct iOSVersion {
static let SYS_VERSION_FLOAT = (UIDevice.currentDevice().systemVersion as NSString).floatValue
static let iOS7 = (Version.SYS_VERSION_FLOAT < 8.0 && Version.SYS_VERSION_FLOAT >= 7.0)
static let iOS8 = (Version.SYS_VERSION_FLOAT >= 8.0 && Version.SYS_VERSION_FLOAT < 9.0)
static let iOS9 = (Version.SYS_VERSION_FLOAT >= 9.0 && Version.SYS_VERSION_FLOAT < 10.0)
}
Usage:
if iOSVersion.iOS8 {
//Do iOS8 code here
}

Here is a Swift version of yasirmturk macros. Hope it helps some peoples
// MARK: System versionning
func SYSTEM_VERSION_EQUAL_TO(v: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(v, options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedSame
}
func SYSTEM_VERSION_GREATER_THAN(v: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(v, options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending
}
func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(v, options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedAscending
}
func SYSTEM_VERSION_LESS_THAN(v: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(v, options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedAscending
}
func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(v, options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedDescending
}
let kIsIOS7: Bool = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO("7")
let kIsIOS7_1: Bool = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO("7.1")
let kIsIOS8: Bool = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO("8")
let kIsIOS9: Bool = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO("9")

Related

How to detect iOS device programmatically

I need to know which iOS device is currently running app (saying more exactly I need to know is device armv6 or armv7). UIUserInterfaceIdiomPad() could not check is device an iPhone4S or iPhone3G. Is it possible?
Download https://github.com/erica/uidevice-extension (UIDevice-Hardware class) and you can use these:
[UIDevice currentDevice] platformType] // returns UIDevice4GiPhone
[[UIDevice currentDevice] platformString] // returns #"iPhone 4G"
Or check if its retina
+ (BOOL) isRetina
{
if([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
return [[UIScreen mainScreen] scale] == 2.0 ? YES : NO;
return NO;
}
Or check iOs version
+ (BOOL) isIOS5
{
NSString *os5 = #"5.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
// currSysVer = #"5.0.1";
if ([currSysVer compare:os5 options:NSNumericSearch] == NSOrderedAscending) //lower than 4
{
return NO;
}
else if ([currSysVer compare:os5 options:NSNumericSearch] == NSOrderedDescending) //5.0.1 and above
{
return YES;
}
else // IOS 5
{
return YES;
}
return NO;
}
If you really want to know (at run time) if you are running on arm6 or arm7, you can use "NXGetArchInfoFromCPUType" (much more detail is available in the accepted answer to this question).
Otherwise you can use platformType or platformString, as our incredibly quick answering friend Omar suggested (and +1 to him!).

How to build app with iOS 5.0 methods for iOS 4.3?

I'm finishing iCloud feature for my app and can't solve one problem:
Since I'm using some new 5.0 features like NSFileCoordinator, I can't build my app for 4.3 because of "dyld: Symbol not found: _OBJC_CLASS_$_NSFileCoordinator".
How can I "untarget" some files (which have iCloud methods) for building 4.3 version?
Thanks in advance!
Have a look at this.
Class cls = NSClassFromString (#"NSFileCoordinator");
if (cls) {
// Create an instance of the class and use it.
} else {
// Alternate code path to follow when the
// class is not available.
}
Also check this answer to see why
you should avoid relying on the version string as an indication of device or OS capabilities.
To just take them out of the source copilation:
Click on your project file.
Go to "Build Phases".
Expand "Compile Sources".
Select the file you dont want, and press the "-" button at the
bottom of the section.
Or you can delete it from the project (just remove the reference rather than deleting the file), and it will remove it from this section as well.
Or you could create preprocessor macros to check to see if the user can run the functions
// System Versioning Preprocessor Macros
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
/* Usage
if (SYSTEM_VERSION_LESS_THAN(#"4.0")) {
...
}
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"3.1.1")) {
...
}*/
With this, you can check to see what systen version the user is using and only build for 5.0, but put in functioning code for if it is a version less than 5.0.
I think it's better to turn off iCloud feature for 4.3 builds altogether. You can do that by check iOS version at runtime. In your particular case you could check for presence of NSFileCoordinator class with NSClassFromString() function, but I'm pretty sure there are more decent ways on the internet of accomplishing this.
You could make a new build target and set a compiler preprocessing Macro like NO_CLOUD and then use
#ifdef NO_CLOUD
... code here ...#else
... cloud code here ... #endif
You have to weak link to the framwork's (when you add a framework to the project just set it as optional not required).
In the h file you have to import only if you have ios 5
#if defined(__IPHONE_5_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0
#import <Twitter/Twitter.h>
#import <Accounts/Accounts.h>
#endif
and in the m file you have to try to create class from string and test to see if you have the class. And also test top see if the class responds to selectors.
Class TWTweetComposeViewControllerClass = NSClassFromString(#"TWTweetComposeViewController");
if (TWTweetComposeViewControllerClass != nil) {
if([TWTweetComposeViewControllerClass respondsToSelector:#selector(canSendTweet)]) {
UIViewController *twitterViewController = [[TWTweetComposeViewControllerClass alloc] init];
[twitterViewController performSelector:#selector(setInitialText:)
withObject:NSLocalizedString(#"TwitterMessage", #"")];
[twitterViewController performSelector:#selector(addURL:)
withObject:url];
[twitterViewController performSelector:#selector(addImage:)
withObject:[UIImage imageNamed:#"yourImage.png"]];
[self.navigationController presentModalViewController:twitterViewController animated:YES];
[twitterViewController release];
}
} else {
//do something else
}
My example is based on twitter engine you have to adapt it to your classes.
Build it with latest SDK (5.0). It will tun both 4.3 and 5.0
And you can check IOS version
if ([[UIDevice currentDevice] systemVersion] floatValue] >= 5.0f) {
// iCloud
} else {
// iCloudless
}

How can we programmatically detect which iOS version is device running on? [duplicate]

This question already has answers here:
How to check iOS version?
(36 answers)
Closed 9 years ago.
I want to check if the user is running the app on iOS less than 5.0 and display a label in the app.
How do I detect which iOS is running on user's device programmatically?
Thanks!
Best current version, without need to deal with numeric search within NSString is to define macros (See original answer: Check iPhone iOS Version)
Those macros do exist in github, see: https://github.com/carlj/CJAMacros/blob/master/CJAMacros/CJAMacros.h
Like this:
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
and use them like this:
if (SYSTEM_VERSION_LESS_THAN(#"5.0")) {
// code here
}
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.0")) {
// code here
}
Outdated version below
to get OS version:
[[UIDevice currentDevice] systemVersion]
returns string, which can be turned into int/float via
-[NSString floatValue]
-[NSString intValue]
like this
Both values (floatValue, intValue) will be stripped due to its type, 5.0.1 will become 5.0 or 5 (float or int), for comparing precisely, you will have to separate it to array of INTs
check accepted answer here: Check iPhone iOS Version
NSString *ver = [[UIDevice currentDevice] systemVersion];
int ver_int = [ver intValue];
float ver_float = [ver floatValue];
and compare like this
NSLog(#"System Version is %#",[[UIDevice currentDevice] systemVersion]);
NSString *ver = [[UIDevice currentDevice] systemVersion];
float ver_float = [ver floatValue];
if (ver_float < 5.0) return false;
For Swift 4.0 syntax
below example is just checking if the device is of iOS11 or greater version.
let systemVersion = UIDevice.current.systemVersion
if systemVersion.cgFloatValue >= 11.0 {
//"for ios 11"
}
else{
//"ios below 11")
}
Update
From iOS 8 we can use the new isOperatingSystemAtLeastVersion method on NSProcessInfo
NSOperatingSystemVersion ios8_0_1 = (NSOperatingSystemVersion){8, 0, 1};
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:ios8_0_1]) {
// iOS 8.0.1 and above logic
} else {
// iOS 8.0.0 and below logic
}
Beware that this will crash on iOS 7, as the API didn't exist prior to iOS 8. If you're supporting iOS 7 and below, you can safely perform the check with
if ([NSProcessInfo instancesRespondToSelector:#selector(isOperatingSystemAtLeastVersion:)]) {
// conditionally check for any version >= iOS 8 using 'isOperatingSystemAtLeastVersion'
} else {
// we're on iOS 7 or below
}
Original answer iOS < 8
For the sake of completeness, here's an alternative approach proposed by Apple itself in the iOS 7 UI Transition Guide, which involves checking the Foundation Framework version.
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
// Load resources for iOS 6.1 or earlier
} else {
// Load resources for iOS 7 or later
}
I know I am too late to answer this question. I am not sure does my method still working on low iOS versions (< 5.0):
NSString *platform = [UIDevice currentDevice].model;
NSLog(#"[UIDevice currentDevice].model: %#",platform);
NSLog(#"[UIDevice currentDevice].description: %#",[UIDevice currentDevice].description);
NSLog(#"[UIDevice currentDevice].localizedModel: %#",[UIDevice currentDevice].localizedModel);
NSLog(#"[UIDevice currentDevice].name: %#",[UIDevice currentDevice].name);
NSLog(#"[UIDevice currentDevice].systemVersion: %#",[UIDevice currentDevice].systemVersion);
NSLog(#"[UIDevice currentDevice].systemName: %#",[UIDevice currentDevice].systemName);
You can get these results:
[UIDevice currentDevice].model: iPhone
[UIDevice currentDevice].description: <UIDevice: 0x1cd75c70>
[UIDevice currentDevice].localizedModel: iPhone
[UIDevice currentDevice].name: Someones-iPhone002
[UIDevice currentDevice].systemVersion: 6.1.3
[UIDevice currentDevice].systemName: iPhone OS
[[UIDevice currentDevice] systemVersion]
[[UIDevice currentDevice] systemVersion];
or check the version like
You can get the below Macros from here.
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(IOS_VERSION_3_2_0))
{
UIImageView *background = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cs_lines_back.png"]] autorelease];
theTableView.backgroundView = background;
}
Hope this helps
[[[UIDevice currentDevice] systemVersion] floatValue]
Marek Sebera's is great most of the time, but if you're like me and find that you need to check the iOS version frequently, you don't want to constantly run a macro in memory because you'll experience a very slight slowdown, especially on older devices.
Instead, you want to compute the iOS version as a float once and store it somewhere. In my case, I have a GlobalVariables singleton class that I use to check the iOS version in my code using code like this:
if ([GlobalVariables sharedVariables].iOSVersion >= 6.0f) {
// do something if iOS is 6.0 or greater
}
To enable this functionality in your app, use this code (for iOS 5+ using ARC):
GlobalVariables.h:
#interface GlobalVariables : NSObject
#property (nonatomic) CGFloat iOSVersion;
+ (GlobalVariables *)sharedVariables;
#end
GlobalVariables.m:
#implementation GlobalVariables
#synthesize iOSVersion;
+ (GlobalVariables *)sharedVariables {
// set up the global variables as a static object
static GlobalVariables *globalVariables = nil;
// check if global variables exist
if (globalVariables == nil) {
// if no, create the global variables class
globalVariables = [[GlobalVariables alloc] init];
// get system version
NSString *systemVersion = [[UIDevice currentDevice] systemVersion];
// separate system version by periods
NSArray *systemVersionComponents = [systemVersion componentsSeparatedByString:#"."];
// set ios version
globalVariables.iOSVersion = [[NSString stringWithFormat:#"%01d.%02d%02d", \
systemVersionComponents.count < 1 ? 0 : \
[[systemVersionComponents objectAtIndex:0] integerValue], \
systemVersionComponents.count < 2 ? 0 : \
[[systemVersionComponents objectAtIndex:1] integerValue], \
systemVersionComponents.count < 3 ? 0 : \
[[systemVersionComponents objectAtIndex:2] integerValue] \
] floatValue];
}
// return singleton instance
return globalVariables;
}
#end
Now you're able to easily check the iOS version without running macros constantly. Note in particular how I converted the [[UIDevice currentDevice] systemVersion] NSString to a CGFloat that is constantly accessible without using any of the improper methods many have already pointed out on this page. My approach assumes the version string is in the format n.nn.nn (allowing for later bits to be missing) and works for iOS5+. In testing, this approach runs much faster than constantly running the macro.
Hope this helps anyone experiencing the issue I had!
In MonoTouch:
To get the Major version use:
UIDevice.CurrentDevice.SystemVersion.Split('.')[0]
For minor version use:
UIDevice.CurrentDevice.SystemVersion.Split('.')[1]
To get more specific version number information with major and minor versions separated:
NSString* versionString = [UIDevice currentDevice].systemVersion;
NSArray* vN = [versionString componentsSeparatedByString:#"."];
The array vN will contain the major and minor versions as strings, but if you want to do comparisons, version numbers should be stored as numbers (ints). You can add this code to store them in the C-array* versionNumbers:
int versionNumbers[vN.count];
for (int i = 0; i < sizeof(versionNumbers)/sizeof(versionNumbers[0]); i++)
versionNumbers[i] = [[vN objectAtIndex:i] integerValue];
* C-arrays used here for more concise syntax.
A simple check for iOS version less than 5 (all versions):
if([[[UIDevice currentDevice] systemVersion] integerValue] < 5){
// do something
};

How do I determine whether the current device is an iPhone or iPad?

In my universal app I need to check if the current device is an iPad or iPhone. How can I do this programmatically? I plan to put the code in my viewDidLoad.
check if UISplitViewController class available on the platform, if so make sure it is iPad using Apple's macro (notice that UIUserInterfaceIdiomPad constant is available only on iOS 3.2 and up).
if (NSClassFromString(#"UISplitViewController") != nil && UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
//currentDeviceType = iPad;
}
else {
//currentDeviceType = iPhone;
}
Proper method to detect device model (iPhone/iPod Touch)?
I use this simple function in all my apps:
#import "isPad.h"
BOOL isPad () {
static BOOL isPad;
static BOOL used = NO;
if (used)
return isPad;
used = YES;
NSRange range = [[[UIDevice currentDevice] model] rangeOfString:#"iPad"];
isPad = range.location != NSNotFound;
return isPad;
}
try this.. this will help you.
NSString *deviceType = [UIDevice currentDevice].model;
if([deviceType isEqualToString:#"iPod touch"]||[deviceType isEqualToString:#"iPhone"]||[deviceType isEqualToString:#"iPad"]){
}
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
// Statements
}
else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
// Statements
}

Check iOS version at runtime?

This is sort of a follow on from my last question. I am using beginAnimations:context: to setup an animation block to animate some UITextLabels. However I noticed in the docs that is says: "Use of this method is discouraged in iOS 4.0 and later. You should use the block-based animation methods instead."
My question is I would love to use animateWithDuration:animations: (available in iOS 4.0 and later) but do not want to exclude folks using iOS 3.0. Is there a way to check to iOS version of a device at runtime so that I can make a decision as to which statement to use?
Simpler solution for anyone who'll need help in the future:
NSArray *versionCompatibility = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
if ( 5 == [[versionCompatibility objectAtIndex:0] intValue] ) { /// iOS5 is installed
// Put iOS-5 code here
} else { /// iOS4 is installed
// Put iOS-4 code here
}
In many cases you do not need to check iOS version directly, instead of that you can check whether particular method is present in runtime or not.
In your case you can do the following:
if ([[UIView class] respondsToSelector:#selector(animateWithDuration:animations:)]){
// animate using blocks
}
else {
// animate the "old way"
}
to conform to version specified in system defines
//#define __IPHONE_2_0 20000
//#define __IPHONE_2_1 20100
//#define __IPHONE_2_2 20200
//#define __IPHONE_3_0 30000
//#define __IPHONE_3_1 30100
//#define __IPHONE_3_2 30200
//#define __IPHONE_4_0 40000
You can write function like this
( you should probably store this version somewhere rather than calculate it each time ):
+ (NSInteger) getSystemVersionAsAnInteger{
int index = 0;
NSInteger version = 0;
NSArray* digits = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
NSEnumerator* enumer = [digits objectEnumerator];
NSString* number;
while (number = [enumer nextObject]) {
if (index>2) {
break;
}
NSInteger multipler = powf(100, 2-index);
version += [number intValue]*multipler;
index++;
}
return version;
}
Then you can use this as follows:
if([Toolbox getSystemVersionAsAnInteger] >= __IPHONE_4_0)
{
//blocks
} else
{
//oldstyle
}
Xcode 7 added the available syntax making this relatively more simple:
Swift:
if #available(iOS 9, *) {
// iOS 9 only code
}
else {
// Fallback on earlier versions
}
Xcode 9 also added this syntax to Objective-C
Objective-C:
if (#available(iOS 9.0, *)) {
// iOS 9 only code
} else {
// Fallback on earlier versions
}
Most of these solutions on here are so overkill. All you need to do is [[UIDevice currentDevice].systemVersion intValue]. This automatically removes the decimal, so there is no need to split the string.
So you can just check it like:
if ([[UIDevice currentDevice].systemVersion intValue] >= 8) {
// iOS 8.0 and above
} else {
// Anything less than iOS 8.0
}
You can also define a macro with this code:
#define IOS_VERSION [[UIDevice currentDevice].systemVersion intValue];
or even include your check:
#define IOS_8PLUS ([[UIDevice currentDevice].systemVersion intValue] >= 8)
Then you just need to do:
if (IOS_8PLUS) {
// iOS 8.0 and above
} else {
// Anything less than iOS 8.0
}
Discouraged is not the same as deprecated.
If you need to support earlier versions of iOS that do not have the block based methods, there is nothing wrong with using the older methods (as long as they haven't been removed, of course).
You can use the version of the Foundation framework to determine the current system version.
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1){
//for earlier versions
} else {
//for iOS 7
}
For my purposes I've written a tiny library that abstracts away the underlying C calls and presents an Objective-C interface.
GBDeviceDetails deviceDetails = [GBDeviceInfo deviceDetails];
if (deviceDetails.iOSVersion >= 6) {
NSLog(#"It's running at least iOS 6"); //It's running at least iOS 6
}
Apart from getting the current iOS version, it also detects the hardware of the underlying device, and gets info about the screen size; all at runtime.
It's on github: GBDeviceInfo. Licensed under Apache 2.
Put this in your Prefix.pch file
#define IOS_VERSION [[[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:#"."] firstObject] intValue]
And then you can check iOS versions like:
if(IOS_VERSION == 8)
{
// Hello 8!
}
else
{
// Hello some other version!
}
Off course if you can use feature detection (and it makes sense for your use case) you should do that.
In MonoTouch:
To get the Major version use:
UIDevice.CurrentDevice.SystemVersion.Split('.')[0]
For minor version use:
UIDevice.CurrentDevice.SystemVersion.Split('.')[1]
A bit nicer and more efficient adaptation to the above solutions:
-(CGPoint)getOsVersion
{
static CGPoint rc = {-1,-1};
if (rc.x == -1) {
NSArray *versionCompatibility = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
rc.x = [versionCompatibility[0] intValue];
rc.y = [versionCompatibility[1] intValue];
}
return rc;
}
now you can
if ([self getOsVersion].x < 7) {
}
HTH