如何检查iOS版本?

908

我想检查设备的iOS版本是否大于3.1.3。我尝试了以下方法:

[[UIDevice currentDevice].systemVersion floatValue]

但是它不起作用,我只想要一个:

if (version > 3.1.3) { }

我该如何实现这个?


7
主持人提示: 随着时间的推移,这个问题已经有了30多个答案。在添加新答案之前,请务必确认您的解决方案尚未提供。 - Matt
5
从 Xcode 7 开始,在 Swift 中使用 if #available(iOS 9, *) {}。从 Xcode 9 开始,在 Objective-C 中使用 if (@available(iOS 11, *)) {} - Cœur
36个回答

1061
/*
 *  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")) {
    ...
}

20
在需要时将此内容保留在头文件中是我能想到的最简单的解决方案。在多种情况下,这比使用 NSClassFromString 检查可用性更可靠。另一个例子是在 iAd 中,如果您在 4.2 版本之前使用 ADBannerContentSizeIdentifierPortrait,则会收到 EXEC_BAD_ACCESS 错误,但是相应的 ADBannerContentSizeIdentifier320x50 在 4.1 版本之后已被弃用。 - Rab
1
我在另一个地方使用它是在UIPageViewController中,并将样式设置为iOS6中的UIPageViewControllerTransitionStyleScroll。 - Paul de Lange
8
无法持续10秒。例如,比较4.10和4.9会得出错误的结果。 - pzulw
9
使用可选的“ .0”数字时应非常小心。例如,在iOS 7.0上,“SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@”7.0.0“)”会给出错误的结果。 - Yan
1
我刚刚测试了将这个放在我的.pch文件中,它非常好用(至少在使用Xcode 5构建时)。 - whyoz
显示剩余3条评论

1049

快速答案...


从Swift 2.0开始,您可以在ifguard中使用#available来保护只应在某些系统上运行的代码。

if #available(iOS 9, *) {}


在Objective-C中,您需要检查系统版本并执行比较。

[[NSProcessInfo processInfo] operatingSystemVersion] 在iOS 8及以上版本中。

从Xcode 9开始:

if (@available(iOS 9, *)) {}


完整答案...

在Objective-C和Swift中很少情况下,最好不要依赖操作系统版本作为设备或操作系统功能的指示。通常有更可靠的方法来检查特定功能或类是否可用。

检查API的存在:

例如,您可以使用NSClassFromString检查当前设备上是否有UIPopoverController

if (NSClassFromString(@"UIPopoverController")) {
    // Do something
}

对于弱链接类,直接向该类发送消息是安全的。值得注意的是,这适用于没有明确标记为“必需”的框架。对于缺少的类,表达式将求值为nil,导致条件失败:
if ([LAContext class]) {
    // Do something
}

一些类(如CLLocationManagerUIDevice)提供了检查设备功能的方法:

if ([CLLocationManager headingAvailable]) {
    // Do something
}

检查符号的存在:

很少情况下,您需要检查常量是否存在。这在iOS 8中引入了UIApplicationOpenSettingsURLString时出现,用于通过-openURL:加载设置应用程序。该值在iOS 8之前不存在。将nil传递给此API会导致崩溃,因此您必须先验证常量的存在:

if (&UIApplicationOpenSettingsURLString != NULL) {
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}

与操作系统版本进行比较:

假设您面临着相对罕见的需要检查操作系统版本的情况。对于针对iOS 8及以上版本的项目,NSProcessInfo包括一种执行版本比较的方法,减少出错的可能性:

- (BOOL)isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion)version

针对旧系统的项目可以使用 UIDevice 上的 systemVersion。苹果在他们的GLSprite示例代码中使用了它。

// 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;
}

如果出于任何原因您决定使用systemVersion,请确保将其视为字符串,否则您有可能会截断补丁修订号(例如3.1.2 -> 3.1)。


162
有一些特定情况需要检查系统版本。例如,在4.0中,一些在3.x版本中为私有的类和方法被改为公开的,因此,如果您仅检查它们的可用性,则会在3.x中得到错误的结果。此外,在3.2及以上版本中,UIScrollView处理缩放比例的方式发生了微妙的变化,因此您需要检查操作系统版本以适当地处理结果。 - Brad Larson
2
iOS 3.2似乎不会在UISplitViewController中发送-viewWillAppear。我的解决方法是确定是否小于iOS 4.0,并在Root View的-didSelectRowAtIndexPath中自己将其发送到Detail View Controller。 - jww
10
这里需要稍微小心,因为[@"10.0" compare:@"10" options:NSNumericSearch]返回的是NSOrderedDescending,这可能并不是预期的结果。(我本来可能希望结果是NSOrderedSame) 至少从理论上讲,这是有可能发生的。 - Ken
如果你只想要版本字符串,自iOS 2.0以来就有一个名为operatingSystemVersionString的方法。 - dcow
2
随着TVos的推出,这变得更加重要。例如,当使用9.1 SDK时,TVos将返回9.0。因此,检查类或方法(选择器)是最好的方法,之后您应该检查NSFoundationVersionNumber,只有在不可能时才应该检查UIDevice上的系统版本。 - rckoenes
显示剩余6条评论

252

根据官方Apple文档的建议:您可以使用来自NSObjCRuntime.h头文件的NSFoundationVersionNumber

if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
    // here you go with iOS 7
}

41
这实际上是此处最安全和最准确的选择。 - mxcl
8
在iOS 5 SDK中不存在NSFoundationVersionNumber_iOS_6_1 - Kjuly
2
@Kjuly,你可以自己定义缺失的版本号:https://github.com/carlj/CJAMacros/blob/master/CJAMacros/CJAMacros.h(查看第102-130行)。 - CarlJ
3
不,你错了,NSFoundationVersionNumber_iOS_7_0不存在。但是我们可以使用#ifndef NSFoundationVersionNumber_iOS_7_0 #define NSFoundationVersionNumber_iOS_7_0 1047.00 #endif来定义它。为了避免混乱,我选择了来自yasirmturk的SYSTEM_VERSION_LESS_THAN(v)宏。 - Cœur
8
不,但是苹果将在iOS 9中添加NSFoundationVersionNumber_iOS_8_0。只需检查NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1即可。 - CarlJ
显示剩余12条评论

139
从Xcode 9开始,在Objective-C中:
if (@available(iOS 11, *)) {
    // iOS 11 (or newer) ObjC code
} else {
    // iOS 10 or older code
}

从Xcode 7开始,在Swift中:
if #available(iOS 11, *) {
    // iOS 11 (or newer) Swift code
} else {
    // iOS 10 or older code
}

关于版本,您可以指定主要版本、次要版本或修订版本(请参考http://semver.org/了解定义)。例如:

  • iOS 11iOS 11.0是相同的最低版本
  • iOS 10iOS 10.3iOS 10.3.1是不同的最低版本

您可以为任何这些系统输入值:

  • iOSmacOSwatchOStvOSvisionOS,等等(请参考文档)

这是一个真实案例,取自我的其中一个库

if #available(iOS 10.0, tvOS 10.0, *) {
    // iOS 10+ and tvOS 10+ Swift code
} else {
    // iOS 9 and tvOS 9 older code
}

可用的文档


我可以在Objective-C中使用guard代替在else语句中保持块的打开和缩进吗? - Legoless
@Legoless 不需要,只需使用一个空的 if 块,然后跟一个 else - Cœur
1
这是我目前的解决方案,只是想避免不必要的缩进和空的 if 块。 - Legoless
以上的 if 语句在操作系统是 11.1.3 的情况下是否有效?还是只检查了 11.0? - Supertecnoboff
if (@available(iOS 11, *)) 这段代码是对 iOS 11 版本进行运行时检查还是编译时检查,还是两者都包含? - Jan
显示剩余5条评论

39

尝试:

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
}

2
为什么不反转顺序并保存比较,因为@"3.1.3"和systemVersion都是NSStrings?即: if ([UIDevice currentDevice].systemVersion compare:@"3.1.3" options:NSNumericSearch] == NSOrderedAscending) ;// OS version < 3.1.3 else ;// OS version >= 3.1.3 - Rob
3
这样做可能会使逻辑不太清晰,但操作应该是等效的。 - Jonathan Grynspan
1
两个整数之间的比较肯定不会很昂贵。 - KPM
这实际上是一个风格问题。消息分发的开销远远超过额外的整数比较。 - Jonathan Grynspan

35

首选方法

在 Swift 2.0 中,苹果公司使用更加方便的语法添加了可用性检查(阅读更多信息)。现在,您可以使用更简洁的语法检查操作系统版本:

if #available(iOS 9, *) {
    // Then we are on iOS 9
} else {
    // iOS 8 or earlier
}

根据Swift新特性,检查respondsToSelector不如采用这种方式。现在,编译器会始终提醒您是否正确保护了代码。


Swift 2.0之前

iOS 8中新增了NSProcessInfo,使得语义版本检查更加精确。

在iOS 8及以上版本上部署

对于最低部署目标为iOS 8.0或更高版本,请使用NSProcessInfooperatingSystemVersionisOperatingSystemAtLeastVersion

这将产生以下结果:

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)
}

在iOS 7上部署

对于最低部署目标是iOS 7.1或以下的情况,可以使用比较符号与UIDevice systemVersion一起使用NSStringCompareOptions.NumericSearch

这将产生以下结果:

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;
}

更多阅读请访问 NSHipster


9

我总是将以下内容保存在我的Constants.h文件中:

#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)

很好。最好将这个放在你的XCode项目的.pch文件中。 - Vaibhav Jhaveri
1
我将所有的常量放在我的 Constants.h 文件中,并在我的 pch 文件中导入。 - Segev

6
+(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;
  }


}

@Jef 版本控制中的句点不是小数点,而且非常重要。你的回答没有忽略这些句点,如果忽略了它们,那么答案就是错误的。在版本控制中,每个由句点分隔的元素都是一个完整的数字。例如:'1.23.45' 大于 '1.2.345',因为第二个元素 '23' 大于 '2'。如果你消除了这些句点,那么这两个数字就是相同的。 - Andres Canella

6
我知道这是一个老问题,但有人应该提到Availability.h中的编译时宏。这里的所有其他方法都是运行时解决方案,不适用于标头文件、类别或实例变量定义。
对于这些情况,请使用
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0 && defined(__IPHONE_14_0)
  // iOS 14+ code here
#else
  // Pre iOS 14 code here
#endif

转载自这个答案


6

使用包含在nv-ios-version项目中的Version类(Apache许可证,版本2.0),可以轻松获取和比较iOS版本。下面是一个示例代码,它会输出iOS版本并检查该版本是否大于或等于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.
}

项目页面:nv-ios-version
TakahikoKawasaki/nv-ios-version

博客:使用Version类在运行时获取和比较iOS版本
使用Version类在运行时获取和比较iOS版本


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接