Using @available with stored properties

chickenparm picture chickenparm · Jan 28, 2017 · Viewed 9.3k times · Source

I have an app that uses local notifications and supports iOS 10. I am trying to add iOS 9 support which requires me to use the old location notification API. I am trying to use @available and #available on my iOS 10 code and I can't figure out how to get my center variable to only be for devices running iOS 10.

When I set my target from iOS 10 to 9 I get the error message for this variable: "UNUserNotificationCenter is only available on iOS 10.0 or newer." It suggests I add "@available(iOS 10.0, *)" to my entire class which I don't want to do since there is code in this class that will be used for iOS 9. I appreciate any suggestions on how to limit my center property to just iOS 10.

class ViewController: UIViewController, UITextFieldDelegate {

  let center = UNUserNotificationCenter.current()
  ...

Answer

kgaidis picture kgaidis · Apr 19, 2017

Here is one potential solution (thanks to blog post). The idea is to use a stored property with a type of Any and then create a computed property that will cast the stored property (and instantiate it if necessary).

private var _selectionFeedbackGenerator: Any? = nil
@available(iOS 10.0, *)
fileprivate var selectionFeedbackGenerator: UISelectionFeedbackGenerator {
    if _selectionFeedbackGenerator == nil {
        _selectionFeedbackGenerator = UISelectionFeedbackGenerator()
    }
    return _selectionFeedbackGenerator as! UISelectionFeedbackGenerator
}

Another option is to use lazy (however, this makes the variable read-write):

@available(iOS 10.0, *)
private(set) lazy var center = UNUserNotificationCenter.current()