Swift,为iOS 7和8编写代码。

17

我正在使用Swift编写一个测试应用程序,我想要面向iOS 7。但是为了启用本地通知,我需要添加

application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: UIUserNotificationType.Sound 
    | UIUserNotificationType.Alert 
    | UIUserNotificationType.Badge, 
    categories: nil))

但是这个调用在iOS 7中不可用,所以我添加了

var version:NSString = UIDevice.currentDevice().systemVersion as NSString;
if  version.doubleValue >= 8 {
    // ios 8 code
}

这段代码只在iOS 8及以上版本中运行(已测试),但在iOS 7中运行应用程序时仍会出现以下错误:

dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings Referenced from: /var/mobile/Applications/AC73969D-1A4C-45AC-99CA-0B3982C1EE36/Timely.app/Timely Expected in: /System/Library/Frameworks/UIKit.framework/UIKit in /var/mobile/Applications/AC73969D-1A4C-45AC-99CA-0B3982C1EE36/Timely.app/Timely

我认为这是因为二进制文件包含了在iOS 7中不存在的API符号,但我该如何解决这个问题?


你在什么时候看到这个错误? - jrturton
如果将项目的目标更改为iOS7会发生什么?我猜(至少在测试版中)当您编译应用程序时,它会继续放置所有iOS8符号,而当它在iOS7上使用dyld将所有内容链接在一起时,它会发现许多iOS8特有的东西无法理解。 - Ephemera
1
据我所知,如果部署目标不是iOS 7或更低版本,则无法选择在iOS 7上部署。 - CodeSmile
有什么进展吗?我现在也被这个问题困扰了... - Byron Coetsee
这个问题似乎在Xcode 6 beta 6中已经被修复了。 - user102008
显示剩余4条评论
5个回答

2
很遗憾,我认为您遇到了当前的限制,请参见此链接:什么是Swift预处理器相当于iOS版本检查比较?。唯一的解决方法是添加一个Objective-C文件,然后使用#if宏并创建两个帮助函数,从Swift调用它们(一个用于iOS8,一个用于iOS7)。我期望这个问题在某个时候会得到解决。

2
这里不适合使用#if。系统版本在编译时无法确定。同一个二进制文件可用于iOS7和iOS8。 - Bryan Chen
这实际上是有效的,通过在 Objective-C 中检查 UIDevice 系统版本,应用程序没有抱怨未知符号,可惜这是一种 hack。 - Charlie Wu
这只是暂时的。我非常确定这是一个错误。你可能想要提交一个Radar。 - Lou Franco
你不需要使用 #if,因为正如 Bryan Chen 所说,问题是在运行时而不是编译时出现的。这只有通过将代码转换为 Objective-C 才能“解决”,我们已经知道 Objective-C 编译器会正确地弱链接那些仅在部署目标版本之后才可用的符号。 - user102008

1
在Beta6中,似乎已经修复了一些(全部?)链接问题。使用UIAlertAction和UIAlertController链接的应用程序以前无法在7.1上启动,但现在可以启动。您仍然无法在7.1中使用它们,但可以测试iOS版本并使用旧对象。

0

这里有一个非常好的答案,作者是Prasath,但它是用Objective-C编写的,
所以我用Swift写了类似的东西:

(在Xcode 6中测试过)

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

   // ...

   // Set Notification

   if UIApplication.sharedApplication().respondsToSelector(Selector("registerUserNotificationSettings:")) {

      // Notifications for iOS 8
      let notificationSettings = UIUserNotificationSettings(forTypes: .Alert | .Sound, categories: nil)
      UIApplication.sharedApplication().registerUserNotificationSettings(notificationSettings)
   }
   else {
      // Notifications for iOS < 8
      UIApplication.sharedApplication().registerForRemoteNotificationTypes(.Alert | .Sound)
   }

   // ...

   return true
}

希望这有所帮助


0

这有点不太正规,但对我来说可行:

if(UIApplication.sharedApplication().respondsToSelector("isRegisteredForRemoteNotifications")){ println("is iOS8") }

0
我遇到了类似的问题,所以对于任何遇到这个问题的人,这里有另一个可能的解决方案:
如果您进入目标 > 通用 > 链接的框架和库,您应该会看到UIKit(如果没有,请添加)。确保它旁边写着“可选”,而不是“必需”...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接