Checking for quick actions availability - ios

I'm using home screen quick actions that's only supported in IOS9.
Using the constant UIApplicationLaunchOptionsShortcutItemKey will crash if used in IOS8.
What is the correct way to check if quick actions is supported?
One way is to check for IOS9 through systemVersion but I'm hoping there is a better way.
[[UIDevice currentDevice] systemVersion]

In objective C you can check to see if a class exists. Say something like
if([UIApplicationShortcutItem class]){
//Handle shortcut launch
}

I think in case of Swift the best way for checking the API availability is Automatic operating system API availability checking that's new feature released with iOS9 and Swift2
if #available(iOS 9, *) {
// use UIApplicationLaunchOptionsShortcutItemKey
} else {
// no available
}
#available is going to check whether are we using iOS 9 or later, or any other unknown platforms like watchOS so the * is also here.
If your code is inside a function then you can use #available with guard like this.
guard #available(iOS 9, *) else {
return
}
Mark your methods and class as well like
#available(iOS 9, *)
func useMyStackView() {
// use UIStackView
}
#available works similarly to #available so If your deployment target is iOS7 or less than 9, you can't call that useMyStackView()

For Objc, it also can use #available (iOS 9, *) to check the OS version
if (#available(iOS 9, *)) {
//use UIApplicationLaunchOptionsShortcutItemKey
}

Related

How to subclass a renamed class? / 'MKPinAnnotationView' was deprecated in iOS 15.0: renamed to 'MKMarkerAnnotationView‘

MKPinAnnotationView was renamed in iOS 15 to MKMarkerAnnotationView.
Up to iOS 14, I subclassed MKPinAnnotationView as
class MyAnnotationView: MKPinAnnotationView {
// …
}
The problem:
If my app is compiled to iOS 14, I want to declare MyAnnotationView as above.
However if it is compiled to iOS 15, I have to use
class MyAnnotationView: MKMarkerAnnotationView {
// …
}
How can this be achieved?
On the instruction level, I could use something like
if #available(iOS 15, *) {
// iOS 15
} else {
// iOS 14
}
But on the class level, apparently only something like
#available(iOS 15, *)
class MyAnnotationView: MKMarkerAnnotationView {
seems to be available that lets me compile a class if iOS 15 is available, but apparently I cannot avoid compilation of class MyAnnotationView: MKPinAnnotationView { if iOS 15 is available.
So how is this handled in Swift?
As noted by #Paulw11 in other answer, MKMarkerAnnotationView has been available since iOS 11. So there's no need to be on iOS 15 to use it.
This part is still relevant to other cases like #dfd mentioned for image picker on iOS 14 and earlier versions.
Not as pretty as it should be, it's worth a shot anyway.
import MapKit
#if canImport(CoreLocationUI) // Hack for iOS 15?
public typealias BaseAnnotationView = MKMarkerAnnotationView
#else
public typealias BaseAnnotationView = MKPinAnnotationView
#endif
class MyAnnotationView: BaseAnnotationView {
}
MKPinAnnotationView hasn't been renamed.
MKPinAnnotationView is deprecated in iOS 15, but you can still use it. Deprecation just means it isn't recommended that you use it for new apps, it may go away in the future and you can't expect any enhancements.
MKMarkerAnnotationView has been available since iOS 11, so unless your app is targeting iOS 10 or earlier you can simply switch to using it instead of MKPinAnnotationView

Expected Declaration when Checking iOS Version in Swift 5

I want to add iOS version checking on my code, however, I always got this error
if #available(iOS 13.4, *) {
var tagSession: NFCTagReaderSession!
} else {
}
I can't use #available(iOS 13.0, *) because I still want to use this scene for below iOS 13.
Does anyone know how to solve the problem? Thank you in advance!

Swift - Use both UIAlertController & UIAlertView for iOS 7 / iOS 8 and above

My app's deployment target is 7.0 . I want to use both UIAlertController and UIAlertView. I read somewhere that checking for iOS versions is not good, so i used this code :
if (NSClassFromString("UIAlertController") != nil) {
// UIAlertController
} else {
// UIAlertView
But even if do that, i still get that "correctable" error "UIAlertController is only available on iOS 8.0 or newer" and i have to choose between 3 'Fix-it' options :
Add 'if #available' version check ( if #available(iOS 8.0, *) { ... } else { ... })
Add #available attribute to enclosing instance method
Add #available attribute to enclosing class
What should i do ? Currently using Xcode 7 GM
As stated, the best way to do this is using the #available function. I've attached a code example for you.
if #available(iOS 8.0, *) {
} else {
}
#available is the best way to do these checks.

Detecting available API iOS vs. watchOS in Swift

#available does not seem to work when differentiating between watchOS and iOS.
Here is an example of code shared between iOS & watchOS:
lazy var session: WCSession = {
let session = WCSession.defaultSession()
session.delegate = self
return session
}()
...
if #available(iOS 9.0, *) {
guard session.paired else { throw WatchBridgeError.NotPaired } // paired is not available
guard session.watchAppInstalled else { throw WatchBridgeError.NoWatchApp } // watchAppInstalled is not available
}
guard session.reachable else { throw WatchBridgeError.NoConnection }
Seems that it just defaults to WatchOS and the #available is not considered by the compiler.
Am I misusing this API or is there any other way to differentiate in code between iOS and WatchOS?
Update: Seems like I was misusing the API as mentioned by BPCorp
Using Tali's solution for above code works:
#if os(iOS)
guard session.paired else { throw WatchBridgeError.NotPaired }
guard session.watchAppInstalled else { throw WatchBridgeError.NoWatchApp }
#endif
guard session.reachable else { throw WatchBridgeError.NoConnection }
Unfortunately there is no #if os(watchOS) .. as of Xcode 7 GM
Edit: Not sure when it was added but you can now do #if os(watchOS) on Xcode 7.2
If you want to execute that code only on iOS, then use #if os(iOS) instead of the if #available(iOS ...).
This way, you are not using a dynamic check for the version of your operating system, but are compiling a different code for one OS or the other.
In the Apple dev guide, it is said that the star, * (which is required) means that it will execute the if body for OSes not specified but listed in the minimum deployment target specified by your target.
So, if your target specifies iOS and watchOS, your statement if #available(iOS 9.0, *) means that the ifbody is available for iOS 9 and later and any watchOS version.
Also, be careful if you want to use what's described in the chapter "Build Configurations" in this Apple guide. It is used to conditionally compile your code based on the operating system. This is not dynamic at runtime.
With the GM version of Xcode7 I think they fixed that issue. For me :
if #available(watchOS 2,*) {
// Only if using WatchOS 2 or higher
}
is working fine in GM version.
Time have passed since the question. If somebody still looking for the answer, need to say that
#if os(watchOS)
is now available in Xcode 13 and later.

Check for class existence in Swift

I want to use NSURLQueryItem in my Swift iOS app. However, that class is only available since iOS 8, but my app should also run on iOS 7. How would I check for class existence in Swift?
In Objective-C you would do something like:
if ([NSURLQueryItem class]) {
// Use NSURLQueryItem class
} else {
// NSURLQueryItem is not available
}
Related to this question is: How do you check for method or property existence of an existing class?
There is a nice section in https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/AdvancedAppTricks/AdvancedAppTricks.html#//apple_ref/doc/uid/TP40007072-CH7-SW4 called Supporting Multiple Versions of iOS, which explains different techniques for Objective-C. How can these be translated to Swift?
Swift 2.0 provides us with a simple and natural way to do this.It is called API Availability Checking.Because NSURLQueryItem class is only available since iOS8.0,you can do in this style to check it at runtime.
if #available(iOS 8.0, *) {
// NSURLQueryItem is available
} else {
// Fallback on earlier versions
}
Simplest way I know of
if NSClassFromString("NSURLQueryItem") != nil {
println("NSURLQueryItem exists")
}else{
println("NSURLQueryItem does not exists")
}
Try this:
if objc_getClass("NSURLQueryItem") != nil {
// iOS 8
} else {
// iOS 7
}
I've also done it like this too:
if let theClass: AnyClass = NSClassFromString("NSURLQueryItem") {
// iOS 8
} else {
// iOS 7
}
Or, you can also check system version like so, but this isn't the best practice for iOS dev - really you should check if a feature exists. But I've used this for a few iOS 7 hacks... pragmatism over purity.
switch UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch) {
case .OrderedSame, .OrderedDescending:
iOS7 = false
case .OrderedAscending:
iOS7 = true
}

Resources