Hi all,
a heads up on my observations during porting our quickstart app [1] (Swift port) and
making it compatible to also run on iOS 7 too [2]. Indeed, Swift apps can run on iOS 7
due to the swift-runtime embedded in the application (and can be observed on the generated
app archive [3] ).
A major obstacle faced is that although you can utilise at runtime a form of dynamic
version check (e.g. respondsToSelector[] ) to decide to call either iOS 7 or iOS 8 API,
the runtime is strict on class loading and fails even when the code-path that instantiates
the class is not executed.
Let me give you a concrete example. Here is snippet of code that uses either the new push
registration API available in iOS 8 or fails back to the old one if not:
--
if application.respondsToSelector(Selector("registerUserNotificationSettings:"))
{
let settings = UIUserNotificationSettings(forTypes: .Alert | .Badge | .Sound,
categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
} else {
UIApplication.sharedApplication().registerForRemoteNotificationTypes( .Badge | .Sound
| .Alert)
}
If your Target build SDK is set to ‘Latest (8.0)’ (to avoid compilation error of missing
classes) but your deployment target is set to 7.x (to support older versions) and you have
some form of dynamic selection on runtime (e.g .respondsToSelector[] ), this fails when
running on iOS 7 with a missing symbol: (note that the code path that instantiates
UIUserNotificationSettings is not reached but yet fails at runtime)
--
dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings
Referenced from:
/var/mobile/Applications/E8C53BD1-285E-4DDD-B71C-C99D61195671/Contacts.app/Contacts
Expected in: /System/Library/Frameworks/UIKit.framework/UIKit
in /var/mobile/Applications/E8C53BD1-285E-4DDD-B71C-C99D61195671/Contacts.app/Contacts
--
In contrast, the obj-c version of the same code runs fine on iOS 7.
Apparently this has been observed [4] and some workarounds exist (basically use an
objective-c bridge to workaround it, but that is just a ‘hack'). This is to the fact
that the obj-c compiler does some form of weak-linking the symbols that are only available
on later versions than the deployment target.
I imagine having the same form of issues when trying to utilise a any new iOS 8 class that
doesn’t exist on iOS 7. For that matter (at least for the current state of the Swift
runtime) i am leading towards not using any hacks to workaround issues on Swift running on
iOS 7. I am sure Apple with the current pace of dev will come up with techniques, but
let’s not pollute the code for the time being.
Let me know your thoughts.
-
Christos
[1]
https://github.com/aerogear/aerogear-push-quickstarts/tree/swift
[2]
https://github.com/cvasilak/aerogear-push-quickstarts/tree/swift-ios7
[3]
http://tinyurl.com/swift-runtime
[4]
http://stackoverflow.com/questions/24256583/swift-write-code-for-ios-7-and-8