Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using @available with stored properties

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()   ... } 
like image 215
chickenparm Avatar asked Jan 27 '17 23:01

chickenparm


People also ask

Can extension have stored properties?

Extensions can add new computed properties, but they can't add stored properties, or add property observers to existing properties.

Why extensions Cannot have stored properties?

1 Answer. Extensions cannot contain stored instance properties. Why? Because adding an instance property would change the size of instances of that type.

What are stored properties?

Stored Properties. In its simplest form, a stored property is a constant or variable that's stored as part of an instance of a particular class or structure. Stored properties can be either variable stored properties (introduced by the var keyword) or constant stored properties (introduced by the let keyword).


2 Answers

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() 
like image 134
kgaidis Avatar answered Oct 01 '22 15:10

kgaidis


I know this is an older question but I wanted to add an answer for people who come here via Google as I did.

As kgaidis and Cœur mentioned, you can use @available on computed properties. However, lazy variables are considered computed properties and so you can use @available on them too. This has the nice benefit of removing the boilerplate of the extra stored property and the forced casts - in fact, it leaves no evidence of the property in your pre-iOS 10 code.

You can simply declare it like this:

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

Unfortunately there's no way to make it completely read-only but the private(set) at least makes it read-only outside of the class.

like image 38
Jayson Avatar answered Oct 01 '22 15:10

Jayson