什么是Swift预处理器相当于iOS版本检查比较?

我正进入(状态

yld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings 

这里是当应用程序在iOS7设备上运行时导致错误的function,甚至在代码中甚至没有调用该函数。

 func reigsterForRemoteUserNotifications(notificationTypes: UIUserNotificationType, categories: NSSet) { let userNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: categories) (UIApplication.sharedApplication()).registerUserNotificationSettings(userNotificationSettings) UIApplication.sharedApplication().registerForRemoteNotifications() } 

在iOS7设备上运行时,我不希望这个方法可以被访问。 我不想在它内部进行select检查,因为这意味着该方法可用于开始。

我想要的是一个build立configuration参数来检查版本:我不能找出一种方法来编写一个快速的等效的预处理器macros来检查正确的iOS版本,忽视新的和未声明的iOS 8库函数。

 #if giOS8OrGreater // declare the functions that are iOS 8 specific #else // declare the functions that are iOS 7 specific #endif 

在文档中,苹果build议函数和generics来代替复杂的macros,但在这种情况下,我需要一个构buildconfiguration预编译检查来避免处理未声明的函数。 有什么build议么。

Constants.swift

Swift 1:

 let Device = UIDevice.currentDevice() private let iosVersion = NSString(string: Device.systemVersion).doubleValue 

Swift 2:

 let Device = UIDevice.currentDevice() private let iosVersion = Double(Device.systemVersion) ?? 0 let iOS8 = iosVersion >= 8 let iOS7 = iosVersion >= 7 && iosVersion < 8 

然后在其他文件中

 if iOS8 { } else { } 

所有在这里发布的答案是可怕的,忽略任何单一的检查系统版本的正确方法。 你绝对不应该使用: Device.systemVersion你不应该自定义macros来检查版本号,你不应该超越苹果专门为这个任务定义的库。

这里有详细的文章。

请注意,Swift 2.0允许您通过以下方式直接检查OS版本号是否可用:

 if #available(iOS 10.0, *) { // modern code } else { // Fallback on earlier versions } 

在Swift 2.0之前,推荐的方法是通过系统macros提供的:

  if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_9_0) { // do stuff for iOS 9 and newer } else { // do stuff for older versions than iOS 9 } 

或通过:

  if NSProcessInfo().isOperatingSystemAtLeastVersion(NSOperatingSystemVersion(majorVersion: 10, minorVersion: 0, patchVersion: 0)) { // modern code } 

对于超出系统macros的任何内容。

任何其他方法都被视为不可靠,苹果公司不推荐。 实际上有一个方法会在iOS 10中破解。

请注意,如果您需要在支票中使用类似macros的function,并且想要使用#available ,则可以使用@available定义的@available ,如下所示:

  @available(iOS 7, *) func iOS7Work() { // do stuff if #available(iOS 8, *) { iOS8Work() } } @available(iOS 8, *) func iOS8Work() { // do stuff if #available(iOS 9, *) { iOS9Work() } } @available(iOS 9, *) func iOS9Work() { // do stuff } 

有关Swift中属性的更多信息,可以参考Apple的文档 。

var systemVersion = UIDevice.currentDevice()。systemVersion

更新:这是固定在Xcode 6testing版6(build立6A280e)


这里有一个(也许不是很好)的解决方法:显式地链接到UIKit弱(我知道import语句应该已经链接到框架,但是我们明确地这样做)。

  • 点击Xcode中的项目
  • 在左上angular的下拉列表中select目标
  • 转到常规选项卡
  • 向下滚动到链接的框架和库
  • 添加UIKit.framework
  • 将状态从必需更改为可选

这可能会导致UIKit的所有弱连接,这可能会影响性能。 不确定。

在Objective-C中,即使使用Required,编译器也会自动弱连接其可用性高于部署目标的符号,并使其他链接强连接。 我不知道为什么这不适用于Swift。

根据苹果公司的说法,在Swift中没有预处理器的调用,但是Swift代码可以根据对两个函数的构buildconfiguration的评估进行条件编译。 现在,我们得到os()来selectOSX或iOS, arch()可以selectx86_64,arm,arm64或i386。 所以,你可以评估#if os(iOS) ,但不是#if os(iOS8) (尽pipe对于更高版本的Swift来说这似乎是一个好主意)。

你可以通过检查iOS版本 –

 let iosVersion = UIDevice.currentDevice().systemVersion 

并使用NSStringCompareOptions.NumericSearch进行比较

 switch iosVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch) { case .OrderedSame, .OrderedDescending: //iOS>=8.0.0 return LAContext() case .OrderedAscending: //iOS<8.0.0 return nil } 

您也可以使用新的NSProcessInfo API,但它们不适用于iOS 7。

 if NSProcessInfo().isOperatingSystemAtLeastVersion(NSOperatingSystemVersion(majorVersion: 8, minorVersion: 0, patchVersion: 0)) { //iOS>=8.0.0 } 

你可以在这里看到更多的细节。 希望这可以解决您的查询。

由唯一的亚马逊详细的post: http : //nshipster.com/swift-system-version-checking/

在Swift中检查iOS版本的解决scheme

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

这个解决scheme的概念:检查操作系统版本号,无论采用哪种方式,都是不好的做法。 一个人不应该以这种方式硬编码依赖关系,总是检查function,能力或类的存在。 考虑这个; 苹果可能会发布一个向后兼容的类,如果他们这样做,那么你build议的代码将永远不会使用它,因为你的逻辑查找操作系统的版本号,而不是类的存在。

( 这个信息的来源 )

在Swift中检查类的存在的解决scheme

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

不要使用if (NSClassFromString("UIAlertController") == nil)因为它可以在使用iOS 7.1和8.2的iOS模拟器上正常工作,但是如果你在使用iOS 7.1的真实设备上testing,你将不会注意到,通过代码片段的其他部分。