1.静态检查
静态检查,即在编译时段就检查当前SDK编译与构建应用是否能使用某个API或已经不支持某个API。
编译常量
__IPHONE_OS_VERSION_MIN_REQUIRED
用来判断是否当前SDK版本“仍然”支持或具有某些功能。
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000
//minimum deployment target is 8.0, so it’s safe to use iOS 8-only code
当前SDK最小支持的设备系统,即8.0,所以在iOS 8.0设备上是安全的
#else
//you can use iOS8 APIs, but the code will need to be backwards
//compatible or it will crash when run on an iOS 7 device
你仍然可以使用iOS 8的API,但是在iOS 7的设备上可能会crash.
#endif
__IPHONE_OS_VERSION_MAX_ALLOWED
用来判断是否当前版本“开始”支持或具有某些功能;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
//you can use iOS 10 APIs here because the SDK supports them
//but the code may still crash if run on an iOS 8 device
可以使用最新的iOS 10的API,开始支持的新功能。但是仍然可能会在iOS 8的设备上crash。
#else
//this code can’t use iOS 10 APIs as the SDK version doesn’t support them
不能使用iOS 10的API,只能使用iOS 10之前的。
#endif
针对Xcode的旧版本,或者设备上的就版本,不存在相应的宏,采用如下定义:
#ifndef __IPHONE_10_0 #define __IPHONE_10_0 100000 #endif #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 #else #endif
2.动态检查
CoreFoudation/NSFoundation版本宏
类似于iOS 系统版本宏,系统还给出了CoreFoudation和NSFoudation宏,并且给出了kCFCoreFoundationVersionNumber和NSFoundationVersionNumber两个值。这两个值均是double值。
在iOS10.2.1系统上,以上两个值,分别是:1348.220000、1349.130000。
在Debug下,两个值的存储po出来分别是:1348.22、1349.1300000000001。
kCFCoreFoundationVersionNumber
详见 CoreFoundatin/CFBase.h中定义。
NSFoundationVersionNumber
详见 Foundation/NSObjRuntime.h中定义。
针对上面的宏,写起来复杂,所以可以定义一个宏,来简化书写:
#ifndef kCFCoreFoundationVersionNumber_iPhoneOS_10_0 #define kCFCoreFoundationVersionNumber_iPhoneOS_10_0 1299 #endif #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 #define IF_IOS10_OR_GREATER(...) if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_10_0) { __VA_ARGS__ } #else #define IF_IOS10_OR_GREATER(...) #endif #define IF_PRE_IOS10(...) if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_10_0) { __VA_ARGS__ }
IF_IOS10_OR_GREATER
和IF_PRE_IOS10
就可以在使用中快捷调用。
IF_IOS10_OR_GREATER ( //iOS 10 code here );
然而,即使上面这种方法可以简单的检查系统版本,你仍然无法保证绝对正确,因为你会发现以上宏中不同的系统版本中存在相同的值。
缺陷:当你要判断那些刚好存在相同值的版本的时候,也是一个危险的判断。
3.检查运行的iOS 系统版本
if ([[ [UIDevice currentDevice] systemVersion] floatValue] >= 10.0) { }
注意:上面的判断方法,在判断整数版本的时候,使用起来挺方便,也不会出什么大问题。但是仍然是极其危险的。因为float在计算机中的存储,是近似而非精确。
比如,最新的iOS 10.2.1系统,有以下一段代码:
NSString *version = [[UIDevice currentDevice] systemVersion]; int int_ver = [version intValue]; float float_ver = [version floatValue]; NSLog(@"%@-%d-%f",version,int_ver,float_ver);
打印出来如下的结果:
10.2.1-10-10.200000
可以看出,10.2.1打印出来的floatValue值,是【10.20000】,这还算小事。更为致命的是,在控制台调试时发现:
所以,假如比较10.2.1和10.2.2比较,就很难得出结果。
鉴于此,以上方法不推荐使用!最好不用!
那么,什么是好的运行时判断系统的方法呢?
定义判断版本的宏:
#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)
|
但是,由于NSString的compare方法本身的缺陷:
NSInteger compareResult = [@"10.0" compare:@"10" options:NSNumericSearch];
遗憾的是,上面的系统版本判断也是有漏洞的。但是相对于之前的漏洞,这个漏洞似乎可以接受。上面返回的结果:NSOrderedDescending,即10.0相比于10是低版本。
4.iOS 8之后,NSOperatingSystemVersion
NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
NSProcessInfo
还提供了:
NSOperatingSystemVersion v = (NSOperatingSystemVersion){8,1,3}; if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:v]) { }
以上这个方法,只有在iOS 8之后,但是对于一些超级APP,仍然在支持iOS 7,所以也就无能为力了。
转自