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

时间:2014-06-11 15:30:30

标签: ios macros swift

我正在

yld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings

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

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

我不希望在iOS7设备上运行时可以访问此方法。我不希望在其中进行选择检查,因为这意味着该方法可用于开始。

我想要的是用于检查版本的build config参数:  我无法找到一种方法来编写一个快速等效的预处理器宏来检查正确的iOS版本并忽略新的和未声明的iOS 8库函数。

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

#endif

在文档中,apple建议使用函数和泛型来替换复杂的宏,但在这种情况下,我需要构建配置预编译检查以避免处理未声明的函数。任何建议。

6 个答案:

答案 0 :(得分:15)

其他答案未提及检查系统版本的正确方法。绝对不应该使用:Device.systemVersion 您不应该使用自定义宏来检查版本号,也不应该超越Apple专门为此任务定义的库。

有一篇很好的文章详细说明了here

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

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

在Swift 2.0之前,建议的方法是通过提供的系统宏:

    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
}

对于系统宏之外的任何遗漏。

任何其他方法都被认为是不可靠的,而不是苹果推荐的。实际上有一种方法会在iOS 10中破解。

请注意,如果您在支票中需要类似宏的功能,并且想要使用#available,则可以使用this article中定义的@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's documentation

答案 1 :(得分:12)

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
{

}

答案 2 :(得分:4)

更新:Xcode 6 beta 6(版本6A280e)修复此问题


这里&#sa;(可能不是那么好)解决方法:明确链接到UIKit弱(我知道import语句应该已经链接到框架,但我们无论如何都要明确地做到这一点)。

  • 点击Xcode中的项目
  • 在左上角的下拉列表中选择目标
  • 转到常规标签
  • 向下滚动到Linked Frameworks and Libraries
  • 添加UIKit.framework
  • 将状态从必需更改为可选

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

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

答案 3 :(得分:4)

var systemVersion = UIDevice.currentDevice()。systemVersion

答案 4 :(得分:3)

根据Apple的说法,Swift中没有预处理程序调用,但Swift代码可以根据两个函数中构建配置的评估进行有条件的编译。现在,我们得到 os()可选择OSX或iOS,arch()可选择x86_64,arm,arm64或i386。因此,您可以评估#if os(iOS),但不能评估#if os(iOS8)(尽管对于Swift的其他版本来说这似乎是一个好主意)。

答案 5 :(得分:1)

您可以通过 -

查看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
}

您可以查看更多详情here。希望这能解决您的问题。