【问题标题】:Check OS version in Swift?在 Swift 中检查操作系统版本?
【发布时间】:2014-08-21 14:01:53
【问题描述】:

我正在尝试在 Swift 中检查系统信息。我想通了,可以通过代码实现:

var sysData:CMutablePointer<utsname> = nil
let retVal:CInt = uname(sysData)

这段代码有两个问题:

  1. sysData 的初始值应该是多少?此示例在 retVal 中给出 -1 可能是因为 sysData 为 nil。
  2. 如何从 sysData 读取信息?

【问题讨论】:

    标签: ios macos swift


    【解决方案1】:

    对于 iOS,请尝试:

    var systemVersion = UIDevice.current.systemVersion
    

    对于 OS X,请尝试:

    var systemVersion = NSProcessInfo.processInfo().operatingSystemVersion
    

    如果您只想检查用户是否至少运行了特定版本,您还可以使用以下适用于 iOS 和 OS X 的 Swift 2 功能:

    if #available(iOS 9.0, *) {
        // use the feature only available in iOS 9
        // for ex. UIStackView
    } else {
        // or use some work around
    }
    

    但不建议检查操作系统版本。与比较版本号相比,最好检查您要使用的功能是否在设备上可用。 对于 iOS,如上所述,您应该检查它是否响应选择器; 例如:

    if (self.respondsToSelector(Selector("showViewController"))) {
        self.showViewController(vc, sender: self)
    } else {
        // some work around
    }
    

    【讨论】:

    • 虽然这对于目标 c 是正确的,但在 swift 中有更好的方法。此处概述...hackingwithswift.com/new-syntax-swift-2-availability-checking
    • 我可以看到直接检查操作系统版本(而不是检查特定功能)的一种用途是收集有关用户之间操作系统版本分布的数据,以确定您的最低部署目标。跨度>
    【解决方案2】:

    更新:
    现在您应该使用 Swift 2 引入的新可用性检查
    例如要检查 iOS 9.0 或更高版本,可以这样:

    if #available(iOS 9.0, *) {
      // use UIStackView
    } else {
      // show sad face emoji
    }
    

    或者可以与整个方法或类一起使用

    @available(iOS 9.0, *)
    func useStackView() {
        // use UIStackView
    }    
    

    或带警卫

    guard #available(iOS 14, *) else {
        return
    }
    

    欲了解更多信息,请参阅this

    更新: 根据艾莉森的评论,我已经更新了答案,检查仍然是运行时,但编译器可以提前知道并且可以在您处理它时显示更好的错误或建议。

    其他检查方式:

    如果您不想要确切的版本,但想使用 if 检查 iOS 9,10 或 11:

    let floatVersion = (UIDevice.current.systemVersion as NSString).floatValue
    

    编辑: 刚刚找到了另一种方法来实现这一点:

    let iOS8 = floor(NSFoundationVersionNumber) > floor(NSFoundationVersionNumber_iOS_7_1)
    let iOS7 = floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_7_1)
    

    【讨论】:

    • 只是一个小的修正:#available 不是编译时检查——相同的二进制文件分发并在所有设备上运行,无论版本如何。这确实有运行时性能损失,因此您可能希望在性能关键代码中避免任何这种情况。
    • @Allison 感谢您提出更正建议,刚刚更新了答案。
    【解决方案3】:

    我制作了从以下链接转移到 swift 中的辅助函数:

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

    func SYSTEM_VERSION_EQUAL_TO(version: String) -> Bool {
        return UIDevice.currentDevice().systemVersion.compare(version,
            options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedSame
    }
    
    func SYSTEM_VERSION_GREATER_THAN(version: String) -> Bool {
        return UIDevice.currentDevice().systemVersion.compare(version,
            options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending
    }
    
    func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
        return UIDevice.currentDevice().systemVersion.compare(version,
            options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedAscending
    }
    
    func SYSTEM_VERSION_LESS_THAN(version: String) -> Bool {
        return UIDevice.currentDevice().systemVersion.compare(version,
            options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedAscending
    }
    
    func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(version: String) -> Bool {
        return UIDevice.currentDevice().systemVersion.compare(version,
            options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedDescending
    }
    

    可以这样使用:

    SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO("7.0")
    

    斯威夫特 4.2

    func SYSTEM_VERSION_EQUAL_TO(version: String) -> Bool {
        return UIDevice.current.systemVersion.compare(version, options: .numeric) == .orderedSame
    }
    
    func SYSTEM_VERSION_GREATER_THAN(version: String) -> Bool {
        return UIDevice.current.systemVersion.compare(version, options: .numeric) == .orderedDescending
    }
    
    func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
        return UIDevice.current.systemVersion.compare(version, options: .numeric) != .orderedAscending
    }
    
    func SYSTEM_VERSION_LESS_THAN(version: String) -> Bool {
        return UIDevice.current.systemVersion.compare(version, options: .numeric) == .orderedAscending
    }
    
    func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(version: String) -> Bool {
        return UIDevice.current.systemVersion.compare(version, options: .numeric) != .orderedDescending
    }
    

    【讨论】:

      【解决方案4】:

      斯威夫特 5

      我们不需要创建扩展,因为ProcessInfo 为我们提供了版本信息。你可以看到下面的 iOS 示例代码。

      let os = ProcessInfo().operatingSystemVersion
      
      switch (os.majorVersion, os.minorVersion, os.patchVersion) {
      case (let x, _, _) where x < 8:
          print("iOS < 8.0.0")
      
      case (8, 0, _):
          print("iOS >= 8.0.0, < 8.1.0")
      
      case (8, _, _):
          print("iOS >= 8.1.0, < 9.0")
      
      case (9, _, _):
          print("iOS >= 9.0.0")
      
      default:
          print("iOS >= 10.0.0")
      }
      

      参考:http://nshipster.com/swift-system-version-checking/

      【讨论】:

      • 最有用的答案。谢谢
      【解决方案5】:

      斯威夫特 5

      func run() {
          let version = OperatingSystemVersion(majorVersion: 13, minorVersion: 0, patchVersion: 0)
          if ProcessInfo.processInfo.isOperatingSystemAtLeast(version) {
              runNewCode()
          } else {
              runLegacyCode()
          }
      }
      
      func runNewCode() {
          guard #available(iOS 13.0, *) else {
              fatalError()
          }
          // do new stuff
      }
      
      func runLegacyCode() {
          // do old stuff
      }
      

      【讨论】:

      • 为什么在 runNewCode 中需要 #available(iOS 11.0, *)?
      • @IllyaKrit #available(...) 块会阻止编译器显示旧版本不支持的代码错误。
      【解决方案6】:

      我制作这个单例是为了简单使用,创建了一个IOSVersion.swift 文件并添加了这段代码:

      import UIKit
      
      public class IOSVersion {
          class func SYSTEM_VERSION_EQUAL_TO(version: NSString) -> Bool {
              return UIDevice.currentDevice().systemVersion.compare(version,
                  options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedSame
          }
      
          class func SYSTEM_VERSION_GREATER_THAN(version: NSString) -> Bool {
              return UIDevice.currentDevice().systemVersion.compare(version as String,
                  options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending
          }
      
          class func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: NSString) -> Bool {
              return UIDevice.currentDevice().systemVersion.compare(version as String,
                  options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedAscending
          }
      
          class func SYSTEM_VERSION_LESS_THAN(version: NSString) -> Bool {
              return UIDevice.currentDevice().systemVersion.compare(version as String,
                  options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedAscending
          }
      
          class func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(version: NSString) -> Bool {
              return UIDevice.currentDevice().systemVersion.compare(version as String,
                  options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedDescending
          }
      }
      

      使用:

      IOSVersion.SYSTEM_VERSION_EQUAL_TO("8.0")
      IOSVersion.SYSTEM_VERSION_LESS_THAN("8.0")
      

      感谢@KVISH

      编辑 Swift 2:

      if #available(iOS 9.0, *) {
          // ? 
      } else {
          // ?
      }
      

      【讨论】:

      • 那是单身吗?或者只是 IOSVersion 上的类函数?单身人士不会是static let shared = IOSVersion
      【解决方案7】:

      详情

      • Xcode 10.2.1 (10E1001)、Swift 5

      链接

      OperatingSystemVersion

      解决方案

      extension OperatingSystemVersion {
          func getFullVersion(separator: String = ".") -> String {
              return "\(majorVersion)\(separator)\(minorVersion)\(separator)\(patchVersion)"
          }
      }
      
      let os = ProcessInfo().operatingSystemVersion
      print(os.majorVersion)          // 12
      print(os.minorVersion)          // 2
      print(os.patchVersion)          // 0
      print(os.getFullVersion())      // 12.2.0
      

      【讨论】:

      • 在使用Double 作为版本号时是否存在潜在的舍入问题,例如10.0999 而不是 10.1?
      • 没有。 var stringVersion = "10.0999"; print(stringVersion.toDouble!) // print 10.0999,它将打印10.0999
      【解决方案8】:

      如果您使用的是 Swift 2,并且想要检查操作系统版本以使用某个 API,则可以使用新的可用性功能:

      if #available(iOS 8, *) {
          //iOS 8+ code here.
      }
      else {
          //Code for iOS 7 and older versions.
          //An important note: if you use #availability, Xcode will also 
          //check that you don't use anything that was introduced in iOS 8+
          //inside this `else` block. So, if you try to use UIAlertController
          //here, for instance, it won't compile. And it's great.
      }
      

      我写这个答案是因为它是 Google 中针对 swift 2 check system version 查询的第一个问题。

      【讨论】:

        【解决方案9】:

        Swift 3.0+ 更新

        func SYSTEM_VERSION_EQUAL_TO(version: String) -> Bool {
            return UIDevice.current.systemVersion.compare(version, options: .numeric) == ComparisonResult.orderedSame
        }
        
        func SYSTEM_VERSION_GREATER_THAN(version: String) -> Bool {
            return UIDevice.current.systemVersion.compare(version, options: .numeric) == ComparisonResult.orderedDescending
        }
        
        func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
            return UIDevice.current.systemVersion.compare(version, options: .numeric) != ComparisonResult.orderedAscending
        }
        
        func SYSTEM_VERSION_LESS_THAN(version: String) -> Bool {
            return UIDevice.current.systemVersion.compare(version, options: .numeric) == ComparisonResult.orderedAscending
        }
        
        func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(version: String) -> Bool {
            return UIDevice.current.systemVersion.compare(version, options: .numeric) != ComparisonResult.orderedDescending
        }
        

        【讨论】:

        • 可以跳过ComparisonResult以使其更短。
        • 另外,将UIDevice.current.systemVersion.compare(version, options: .numeric) 分解为func 有助于代码阅读。
        【解决方案10】:

        在 Swift 2 及更高版本中检查系统版本(以及许多其他版本)的最简单和最简单的方法是:

        if #available(iOS 9.0, *) { // check for iOS 9.0 and later
        
        }
        

        另外,使用#available,您可以检查这些版本:

        iOS
        iOSApplicationExtension
        macOS
        macOSApplicationExtension
        watchOS
        watchOSApplicationExtension
        tvOS
        tvOSApplicationExtension
        swift
        

        【讨论】:

          【解决方案11】:
          let Device = UIDevice.currentDevice()
          let iosVersion = NSString(string: Device.systemVersion).doubleValue
          
          let iOS8 = iosVersion >= 8
          let iOS7 = iosVersion >= 7 && iosVersion < 8
          

          并检查为

          if(iOS8)
          {
          
          }
          else 
          {
          }  
          

          【讨论】:

            【解决方案12】:

            马特汤普森分享了一个非常方便的方法

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

            【讨论】:

              【解决方案13】:

              斯威夫特 4.x

              func iOS_VERSION_EQUAL_TO(version: String) -> Bool {
                  return UIDevice.current.systemVersion.compare(version, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedSame
              }
              
              func iOS_VERSION_GREATER_THAN(version: String) -> Bool {
                  return UIDevice.current.systemVersion.compare(version, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedDescending
              }
              
              func iOS_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
                  return UIDevice.current.systemVersion.compare(version, options: NSString.CompareOptions.numeric) != ComparisonResult.orderedAscending
              }
              
              func iOS_VERSION_LESS_THAN(version: String) -> Bool {
                  return UIDevice.current.systemVersion.compare(version, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedAscending
              }
              
              func iOS_VERSION_LESS_THAN_OR_EQUAL_TO(version: String) -> Bool {
                  return UIDevice.current.systemVersion.compare(version, options: NSString.CompareOptions.numeric) != ComparisonResult.orderedDescending
              }
              

              用法:

              if iOS_VERSION_GREATER_THAN_OR_EQUAL_TO(version: "11.0") {
                  //Do something!
              }
              

              附注KVISH 答案翻译为 Swift 4.x,并重命名了函数,因为我专门将此 sn-p 用于 iOS 应用程序。

              【讨论】:

                【解决方案14】:

                注意:适用于 iOS 8.0 及更高版本。 OS X v10.10 及更高版本

                var majorVersion: Int    { return NSProcessInfo.processInfo().operatingSystemVersion.majorVersion }
                var minorVersion: Int    { return NSProcessInfo.processInfo().operatingSystemVersion.minorVersion }
                var patchVersion: Int    { return NSProcessInfo.processInfo().operatingSystemVersion.patchVersion }
                var myOSVersion:  String { return NSProcessInfo.processInfo().operatingSystemVersionString        }
                

                【讨论】:

                  【解决方案15】:

                  根据 Matt Thompson 的回答,这是一个带有相应单元测试的方法,适用于 iOS 7 及更高版本上的 SwiftObjective-c >(包括 iOS 9 不再让您检查 NSFoundationNumber):

                  + (BOOL) isAtLeastOSVersion:(NSString *)osVersion
                  {
                      switch ([[UIDevice currentDevice].systemVersion compare:osVersion options:NSNumericSearch]) {
                          case NSOrderedSame:
                          case NSOrderedDescending:
                              return YES;
                          default:
                              return NO;
                      }
                  }  
                  

                  .

                  @interface ANFakeCurrDevice : NSObject
                  @property (nonatomic, strong) NSString *systemVersion;
                  @end
                  @implementation ANFakeCurrDevice
                  @end
                  
                  
                  @implementation MyHelperClassUnitTests
                  
                  - (void)setUp {
                      [super setUp];
                  }
                  
                  - (void)tearDown {
                      [super tearDown];
                  }
                  
                  - (void)test_isAtLeastOSVersion
                  {
                      id deviceMock = [OCMockObject niceMockForClass:[UIDevice class]];
                      ANFakeCurrDevice *fakeCurrDevice = [ANFakeCurrDevice new];
                      fakeCurrDevice.systemVersion = @"99.9.9";
                      [[[deviceMock stub] andReturn:fakeCurrDevice] currentDevice];
                      XCTAssertTrue([[UIDevice currentDevice].systemVersion isEqualToString:@"99.9.9"]);
                  
                      fakeCurrDevice.systemVersion = @"1.0.1";
                      XCTAssertTrue([ANConstants isAtLeastOSVersion:@"1"]);
                      XCTAssertTrue([ANConstants isAtLeastOSVersion:@"1.0"]);
                      XCTAssertTrue([ANConstants isAtLeastOSVersion:@"1.0.1"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"1.0.2"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"1.1.0"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"2"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"2.0"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"2.0.0"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"2.0.1"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"2.1.0"]);
                  
                  
                      fakeCurrDevice.systemVersion = @"8.4.0";
                      XCTAssertTrue([ANConstants isAtLeastOSVersion:@"7.0.1"]);
                      XCTAssertTrue([ANConstants isAtLeastOSVersion:@"8"]);
                      XCTAssertTrue([ANConstants isAtLeastOSVersion:@"8.4"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"8.4.1"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"8.4.2"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"9.0"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"9.0.1"]);
                      XCTAssertFalse([ANConstants isAtLeastOSVersion:@"9.0.2"]);
                      XCTAssertTrue([ANConstants isAtLeastOSVersion:@"8.4"] && ![ANConstants isAtLeastOSVersion:@"9.0"]);
                  
                      fakeCurrDevice.systemVersion = @"8.4.1";
                      XCTAssertTrue([ANConstants isAtLeastOSVersion:@"8.4"] && ![ANConstants isAtLeastOSVersion:@"9.0"]);
                  }
                  
                  
                  @end
                  

                  【讨论】:

                  • 你确实意识到实际的方法非常简短和紧凑,我只是添加了单元测试代码来说明和证明它有效,对吧?
                  • 很抱歉,我一眼看不到它是 XCTest。
                  【解决方案16】:
                  let osVersion = NSProcessInfo.processInfo().operatingSystemVersion
                  let versionString = osVersion.majorVersion.description + "." + osVersion.minorVersion.description + "." + osVersion.patchVersion.description
                  print(versionString)
                  

                  【讨论】:

                    【解决方案17】:

                    如果你想检查 WatchOS。

                    斯威夫特

                    let watchOSVersion = WKInterfaceDevice.currentDevice().systemVersion
                    print("WatchOS version: \(watchOSVersion)")
                    

                    目标-C

                    NSString *watchOSVersion = [[WKInterfaceDevice currentDevice] systemVersion];
                    NSLog(@"WatchOS version: %@", watchOSVersion);
                    

                    【讨论】:

                      【解决方案18】:

                      获取当前系统版本并拆分。 所以你可以得到主要和次要版本。

                      let sys_version = UIDevice.current.systemVersion
                      let all_version = sys_version.components(separatedBy: ".")
                      print("Major version : \(all_version[0])")
                      print("Minor version : \(all_version[1])")
                      

                      【讨论】:

                        【解决方案19】:

                        这里编写的大多数示例代码在使用额外零版本时都会得到意想不到的结果。例如,

                        func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
                        return UIDevice.current.systemVersion.compare(version, options: .numeric) != ComparisonResult.orderedAscending
                        }
                        

                        在 iOS“10.3”中通过版本“10.3.0”时,此方法不会返回 true。这种结果没有意义,必须将它们视为相同的版本。为了得到准确的比较结果,我们必须考虑比较版本字符串中的所有数字分量。另外,以所有大写字母提供全局方法并不是一个好方法。由于我们在 SDK 中使用的版本类型是 String,因此在 String 中扩展比较功能是有意义的。

                        要比较系统版本,以下所有示例都应该有效。

                        XCTAssertTrue(UIDevice.current.systemVersion.isVersion(lessThan: "99.0.0"))
                        XCTAssertTrue(UIDevice.current.systemVersion.isVersion(equalTo: UIDevice.current.systemVersion))
                        XCTAssertTrue(UIDevice.current.systemVersion.isVersion(greaterThan: "3.5.99"))
                        XCTAssertTrue(UIDevice.current.systemVersion.isVersion(lessThanOrEqualTo: "10.3.0.0.0.0.0.0"))
                        XCTAssertTrue(UIDevice.current.systemVersion.isVersion(greaterThanOrEqualTo: "10.3"))
                        

                        您可以在我的存储库中查看它 https://github.com/DragonCherry/VersionCompare

                        【讨论】:

                          猜你喜欢
                          • 2016-08-14
                          • 1970-01-01
                          • 2012-02-05
                          • 1970-01-01
                          • 1970-01-01
                          • 2019-09-02
                          • 2019-03-01
                          • 1970-01-01
                          • 2011-07-08
                          相关资源
                          最近更新 更多