1

I want to use a feature that is only available in >= iOS 16 therfore I use the @available flag but it does not work because "Stored properties cannot be marked potentially unavailable with '@available'"

 @available(iOS 16.0, *) @State private var photoPickerItems = [PhotosPickerItem]()
Java
  • 323
  • 3
  • 15
  • Check this out https://github.com/TimmysApp/SImages, this repo handles the picker for you. For displaying multiple images, checkout `MediaSet`. – Timmy Sep 02 '22 at 06:25

2 Answers2

6

In Xcode 14 Release Notes, there are resolved issues.
This is one of them.

Stored properties in Swift can’t have type information that is potentially unavailable at runtime. However, prior to Swift 5.7 the compiler incorrectly accepted @available attributes on stored properties when the property had either the lazy modifier or an attached property wrapper. This could lead to crashes for apps running on older operating systems. The Swift compiler now consistently rejects @available on all stored properties. (82713248) (FB9594187).

So you can no longer use @available on your stored property.

kang_wook
  • 115
  • 1
  • 6
3

That makes sense, and is expected. The memory map of the object’s properties gets defined at compile-time. The compiler wants all instances of your class to contain a fixed set of properties so it knows where to find the properties in memory.

If you want properties to be available or not depending on the OS version, make those properties Optional and then write instance method code that uses an @available to either load a value into each property if the OS is available, or leave it nil if not.

Instead of declaring it as:

 @available(iOS 16.0, *) @State private var photoPickerItems = [PhotosPickerItem]()

Which doesn't work, declare it as

@State private var photoPickerItems: [PhotosPickerItem]? = nil

And then in your initializer, wrap an assignment to that property in an @available. That way, except in iOS ≥ 16, the property will remain nil. In iOS ≥ 16, the @available statement will execute and your property will get a value assigned to it.

(You will then need to rewrite all the code that reads that property to unwrap it, use if let, guard let, the nil coalescing operator, or other ways of dealing with optionals. (Explaining all those is beyond the scope of this answer, and such "nuts and bolts" Swift that if you don't know how to deal with optionals, you should stop and study the subject until you do.)

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • Hey @Duncan, got the [same issue](https://stackoverflow.com/questions/73734383/property-wrapper-stored-properties-cannot-be-marked-potentially-unavailable-with). I'd like to know how to implement this proposed solution. I tried to follow but I'm lost. Can you elaborate more? – Seto Sep 15 '22 at 16:44
  • It would have been neat if it worked this way. – cora Feb 13 '23 at 20:14
  • This only works if the type of the stored property is available on lower version. If, however, the type is the factor forcing you to use @available that solution is not going to work. A workaround might be to declare the stored property as `Any?` and cast it to the correct type on each access. – ali Mar 15 '23 at 12:40
  • @ali, good point. My solution won't work if the type of the property is not defined in older OS versions. Your solution of making it type `Any?` would work, but then you have messy type casting code to deal with. – Duncan C Mar 15 '23 at 14:02