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

[[UIDevice currentDevice].systemVersion floatValue]

但是不管用,我只想要一个:

if (version > 3.1.3) { }

我怎样才能做到这一点呢?


当前回答

在Swift中查看iOS版本的解决方案

switch (UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch)) {
    case .OrderedAscending:
       println("iOS < 8.0")

    case .OrderedSame, .OrderedDescending:
       println("iOS >= 8.0")
}

这个解决方案的缺点:不管你用哪种方式检查OS版本号,这都是一种糟糕的做法。永远不要以这种方式硬编码依赖关系,总是检查特性、功能或类的存在。考虑这一切;苹果可能会发布一个类的向后兼容版本,如果他们这样做了,那么你建议的代码将永远不会使用它,因为你的逻辑是寻找操作系统版本号,而不是类的存在。

(信息来源)

在Swift中检查类存在的解决方案

if (objc_getClass("UIAlertController") == nil) {
   // iOS 7
} else {
   // iOS 8+
}

不要使用if (NSClassFromString("UIAlertController") == nil),因为它在使用iOS 7.1和8.2的iOS模拟器上正常工作,但如果你在使用iOS 7.1的真实设备上测试,你会不幸地注意到你永远不会通过代码片段的else部分。

其他回答

简单的回答是……

从Swift 2.0开始,你可以在if或guard中使用#available来保护那些只能在特定系统上运行的代码。

if #available(iOS 9, *) {} 在Objective-C中,您需要检查系统版本并进行比较。

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

从Xcode 9开始:

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

完整的答案是……

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

检查api的存在:

例如,你可以使用NSClassFromString检查UIPopoverController在当前设备上是否可用:

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

对于弱链接的类,直接向类发送消息是安全的。值得注意的是,这适用于没有显式链接为“Required”的框架。对于缺少的类,表达式的计算结果为nil,不满足条件:

if ([LAContext class]) {
    // Do something
}

一些类,如CLLocationManager和UIDevice,提供了检查设备功能的方法:

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

在Swift中查看iOS版本的解决方案

switch (UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch)) {
    case .OrderedAscending:
       println("iOS < 8.0")

    case .OrderedSame, .OrderedDescending:
       println("iOS >= 8.0")
}

这个解决方案的缺点:不管你用哪种方式检查OS版本号,这都是一种糟糕的做法。永远不要以这种方式硬编码依赖关系,总是检查特性、功能或类的存在。考虑这一切;苹果可能会发布一个类的向后兼容版本,如果他们这样做了,那么你建议的代码将永远不会使用它,因为你的逻辑是寻找操作系统版本号,而不是类的存在。

(信息来源)

在Swift中检查类存在的解决方案

if (objc_getClass("UIAlertController") == nil) {
   // iOS 7
} else {
   // iOS 8+
}

不要使用if (NSClassFromString("UIAlertController") == nil),因为它在使用iOS 7.1和8.2的iOS模拟器上正常工作,但如果你在使用iOS 7.1的真实设备上测试,你会不幸地注意到你永远不会通过代码片段的else部分。

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

然后添加if条件,如下所示:-

if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
   //Your code
}       
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

一般来说,最好是询问一个对象是否可以执行给定的选择器,而不是检查版本号来决定它是否必须存在。

当这不是一个选项,你需要在这里有点小心,因为[@"5.0"比较:@"5"选项:NSNumericSearch]返回nsordereddescent这可能不是有意的;我可能期待NSOrderedSame。这至少是一个理论上的问题,在我看来,这是一个值得防范的问题。

同样值得考虑的是,可能会出现无法合理比较的糟糕版本输入。苹果提供了三个预定义的常量NSOrderedAscending, NSOrderedSame和nsordereddescent,但我可以想到一个叫做NSOrderedUnordered的东西的使用,在我不能比较两个东西的情况下,我想返回一个值来指示这个。

更重要的是,苹果有一天会扩展他们的三个预定义常量以允许各种返回值,这是不可能的,这使得比较不明智。

考虑下面的代码。

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