iOS 判断系统版本

方案一

objc 复制代码
double systemVersion = [UIDevice currentDevice].systemVersion.boolValue;

if (systemVersion >= 7.0) {
    // >= iOS 7.0
} else {
    // < iOS 7.0
}

if (systemVersion >= 10.0) {
    // >= iOS 10.0
} else {
    // < iOS 10.0
}

如果只是大致判断是哪个系统版本,上面的方法是可行的,如果具体到某个版本,如 10.0.1,那就会有偏差。我们知道 systemVersion 依旧是10.0。

方案二

objc 复制代码
NSString *systemVersion = [UIDevice currentDevice].systemVersion;
NSComparisonResult comparisonResult = [systemVersion compare:@"10.0.1" options:NSNumericSearch];

if (comparisonResult == NSOrderedAscending) {
    // < iOS 10.0.1
} else if (comparisonResult == NSOrderedSame) {
    // = iOS 10.0.1
} else if (comparisonResult == NSOrderedDescending) {
    // > iOS 10.0.1
}

// 或者

if (comparisonResult != NSOrderedAscending) {
    // >= iOS 10.0.1
} else {
    // < iOS 10.0.1
}

有篇博客提到这种方法不靠谱。比如系统版本是 10.1.1,而我们提供的版本是 8.2,会返回NSOrderedAscending,即认为 10.1.1 < 8.2 。

其实,用这样的比较方式 NSComparisonResult comparisonResult = [systemVersion compare:@"10.0.1"],的确会出现这种情况,因为默认是每个字符逐个比较,即 1(0.1.1) < 8(.2),结果可想而知。但我是用 NSNumericSearch 方式比较的,即数值的比较,不是字符比较,也不需要转化成NSValue(NSNumber) 再去比较。

方案三

objc 复制代码
if (NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_7_0) {
    // >= iOS 7.0
} else {
    // < iOS 7.0
}

// 或者

if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_7_0) {
    // >= iOS 7.0
} else {
    // < iOS 7.0
}

这些宏定义是 Apple 预先定义好的,如下:

objc 复制代码
#if TARGET_OS_IPHONE
...
#define NSFoundationVersionNumber_iOS_9_4 1280.25
#define NSFoundationVersionNumber_iOS_9_x_Max 1299
#endif

细心的童靴可能已经发现问题了。Apple 没有提供 iOS 10 以后的宏?,我们要判断iOS10.0以后的版本该怎么做呢? 有篇博客中提到,iOS10.0以后版本号提供了,并且逐次降低了,并提供了依据。

objc 复制代码
#if TARGET_OS_MAC
#define NSFoundationVersionNumber10_1_1	425.00
#define NSFoundationVersionNumber10_1_2	425.00
#define NSFoundationVersionNumber10_1_3	425.00
#define NSFoundationVersionNumber10_1_4	425.00
...
#endif

我想这位童鞋可能没仔细看, 这两组宏是分别针对iPhone和macOS的,不能混为一谈的。

所以也只能像下面的方式来大致判断iOS 10.0, 但之前的iOS版本是可以准确判断的。

objc 复制代码
if (NSFoundationVersionNumber > floor(NSFoundationVersionNumber_iOS_9_x_Max)) {
    // > iOS 10.0
} else {
    // <= iOS 10.0
}

方案四

在iOS8.0中,Apple也提供了NSProcessInfo 这个类来检测版本问题。

objc 复制代码
@property (readonly) NSOperatingSystemVersion operatingSystemVersion NS_AVAILABLE(10_10, 8_0);
- (BOOL) isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion)version NS_AVAILABLE(10_10, 8_0);

所以这样检测:

objc 复制代码
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){.majorVersion = 8, .minorVersion = 3, .patchVersion = 0}]) {
     // >= iOS 8.3
} else {
     // < iOS 8.3
}

用来判断iOS 10.0以上的各个版本也是没有问题的,唯一的缺点就是不能准确版本是哪个版本,当然这种情况很少。如果是这种情况,可以通过字符串的比较判断。

方案五

通过判断某种特定的类有没有被定义,或者类能不能响应哪个特定版本才有的方法。 比如,UIAlertController 是在iOS 8.0才被引进来的一个类,我们这个依据来判断版本

objc 复制代码
if (NSClassFromString(@"UIAlertController")) {
    // >= iOS 8.0
} else {
    // < iOS 8.0
}

说到这里,就顺便提一下在编译期间如何进行版本控制,依然用UIAlertController 来说明。

objc 复制代码
NS_CLASS_AVAILABLE_IOS(8_0) @interface UIAlertController : UIViewController

NS_CLASS_AVAILABLE_IOS(8_0) 这个宏说明,UIAlertController 是在iOS8.0才被引进来的API,那如果我们在iOS7.0上使用,应用程序就会挂掉,那么如何在iOS8.0及以后的版本使用UIAlertController ,而在iOS8.0以前的版本中仍然使用UIAlertView 呢?

这里我们会介绍一下在#import <AvailabilityInternal.h> 中的两个宏定义:

*__IPHONE_OS_VERSION_MIN_REQUIRED

*__IPHONE_OS_VERSION_MAX_ALLOWED

从字面意思就可以直到,__IPHONE_OS_VERSION_MIN_REQUIRED 表示iPhone支持最低的版本系统,__IPHONE_OS_VERSION_MAX_ALLOWED 表示iPhone允许最高的系统版本。

__IPHONE_OS_VERSION_MAX_ALLOWED 的取值来自iOS SDK的版本,比如我现在使用的是Xcode Version 8.2.1(8C1002),SDK版本是iOS 10.2,怎么看Xcode里SDK的iOS版本呢?

进入PROJECT,选择Build Setting,在Architectures中的Base SDK中可以查看当前的iOS SDK版本。

打印这个宏,可以看到它一直输出100200。

__IPHONE_OS_VERSION_MIN_REQUIRED 的取值来自项目TARGETS的Deployment Target,即APP愿意支持的最低版本。如果我们修改它为8.2,打印这个宏,会发现输出80200,默认为10.2。

通常,__IPHONE_OS_VERSION_MAX_ALLOWED 可以代表当前的SDK的版本,用来判断当前版本是否开始支持或具有某些功能。而__IPHONE_OS_VERSION_MIN_REQUIRED 则是当前SDK支持的最低版本,用来判断当前版本是否仍然支持或具有某些功能。

回到UIAlertController 使用的问题,我们就可以使用这些宏,添加版本检测判断,从而使我们的代码更健壮。

objc 复制代码
 - (void)showAlertView {
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Title" message:@"message" delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
    [alertView show];
#else
    if (NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_8_0) {
        UIAlertController *alertViewController = [UIAlertController alertControllerWithTitle:@"Title" message:@"message" preferredStyle:UIAlertControllerStyleAlert];

        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
        UIAlertAction *otherAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];

        [alertViewController addAction:cancelAction];
        [alertViewController addAction:otherAction];

        [self presentViewController:alertViewController animated:YES completion:NULL];
    }
#endif
}

方案六

iOS 11.0 以后,Apple加入了新的API,以后我们就可以像在Swift中的那样,很方便的判断系统版本了。

objc 复制代码
if (@available(iOS 11.0, *)) {
	// iOS 11.0 及以后的版本
} else {
	// iOS 11.0 之前
}

参考链接

相关推荐
键盘敲没电5 小时前
【iOS】KVC
ios·objective-c·xcode
不会敲代码的VanGogh7 小时前
【iOS】——应用启动流程
macos·ios·objective-c·cocoa
Magnetic_h1 天前
【iOS】单例模式
笔记·学习·ui·ios·单例模式·objective-c
名字不要太长 像我这样就好2 天前
【iOS】push和pop、present和dismiss
学习·macos·ios·objective-c·cocoa
Magnetic_h4 天前
【iOS】ViewController的生命周期
笔记·学习·ui·ios·objective-c
Magnetic_h4 天前
【iOS】present和push
笔记·学习·ui·ios·objective-c
名字不要太长 像我这样就好6 天前
【iOS】单例模式
开发语言·ios·单例模式·objective-c
键盘敲没电6 天前
【iOS】UIViewController的生命周期
学习·ios·objective-c·xcode
归辞...7 天前
暑假第四周——天气预报仿写
macos·objective-c·cocoa
键盘敲没电9 天前
【iOS】MVC模式
ios·mvc·objective-c·xcode