【发布时间】:2014-08-21 14:01:53
【问题描述】:
我正在尝试在 Swift 中检查系统信息。我想通了,可以通过代码实现:
var sysData:CMutablePointer<utsname> = nil
let retVal:CInt = uname(sysData)
这段代码有两个问题:
- sysData 的初始值应该是多少?此示例在 retVal 中给出 -1 可能是因为 sysData 为 nil。
- 如何从 sysData 读取信息?
【问题讨论】:
我正在尝试在 Swift 中检查系统信息。我想通了,可以通过代码实现:
var sysData:CMutablePointer<utsname> = nil
let retVal:CInt = uname(sysData)
这段代码有两个问题:
【问题讨论】:
对于 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
}
【讨论】:
更新:
现在您应该使用 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 不是编译时检查——相同的二进制文件分发并在所有设备上运行,无论版本如何。这确实有运行时性能损失,因此您可能希望在性能关键代码中避免任何这种情况。
我制作了从以下链接转移到 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")
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
}
【讨论】:
我们不需要创建扩展,因为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")
}
【讨论】:
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
}
【讨论】:
#available(...) 块会阻止编译器显示旧版本不支持的代码错误。
我制作这个单例是为了简单使用,创建了一个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 {
// ?
}
【讨论】:
static let shared = IOSVersion
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
如果您使用的是 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 查询的第一个问题。
【讨论】:
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 有助于代码阅读。
在 Swift 2 及更高版本中检查系统版本(以及许多其他版本)的最简单和最简单的方法是:
if #available(iOS 9.0, *) { // check for iOS 9.0 and later
}
另外,使用#available,您可以检查这些版本:
iOS
iOSApplicationExtension
macOS
macOSApplicationExtension
watchOS
watchOSApplicationExtension
tvOS
tvOSApplicationExtension
swift
【讨论】:
let Device = UIDevice.currentDevice()
let iosVersion = NSString(string: Device.systemVersion).doubleValue
let iOS8 = iosVersion >= 8
let iOS7 = iosVersion >= 7 && iosVersion < 8
并检查为
if(iOS8)
{
}
else
{
}
【讨论】:
马特汤普森分享了一个非常方便的方法
switch UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch) {
case .OrderedSame, .OrderedDescending:
println("iOS >= 8.0")
case .OrderedAscending:
println("iOS < 8.0")
}
【讨论】:
斯威夫特 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 应用程序。
【讨论】:
注意:适用于 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 }
【讨论】:
根据 Matt Thompson 的回答,这是一个带有相应单元测试的方法,适用于 iOS 7 及更高版本上的 Swift 和 Objective-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
【讨论】:
let osVersion = NSProcessInfo.processInfo().operatingSystemVersion
let versionString = osVersion.majorVersion.description + "." + osVersion.minorVersion.description + "." + osVersion.patchVersion.description
print(versionString)
【讨论】:
如果你想检查 WatchOS。
斯威夫特
let watchOSVersion = WKInterfaceDevice.currentDevice().systemVersion
print("WatchOS version: \(watchOSVersion)")
目标-C
NSString *watchOSVersion = [[WKInterfaceDevice currentDevice] systemVersion];
NSLog(@"WatchOS version: %@", watchOSVersion);
【讨论】:
获取当前系统版本并拆分。 所以你可以得到主要和次要版本。
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])")
【讨论】:
这里编写的大多数示例代码在使用额外零版本时都会得到意想不到的结果。例如,
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
【讨论】: