With this sample code here:
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello world")
.hoverEffect(isEnabled: true)
}
}
private extension View {
func hoverEffect(isEnabled: Bool) -> some View {
if #available(iOS 17.0, *) {
// VisionOS 2.0 goes in here?
return self
.hoverEffect(.automatic, isEnabled: isEnabled)
} else {
return self
}
}
}
You would expect if the destination was visionOS it would go into the else block but it doesn't. That seems incorrect since the condition should be true if the platform is iOS 17.0+.
Also, I had this similar code that was distriubted via a xcframework and when that view is used in an app that is using the xcframework while running against visionOS there would be a runtime crash (EXC_BAD_ACCESS
). The crash could only be reproduced when using that view from the xcframework and not the local source code. The problem was fixed by adding visionOS 1.0
to that availability check. But this shouldn't have been a crash in the first place.
Does anyone have thoughts on this or possibly an explanation?
Thank you!
Hello @klinee101,
You would expect if the destination was visionOS it would go into the else block but it doesn't. That seems incorrect since the condition should be true if the platform is iOS 17.0+.
This is a common misconception about what the "*" does in that availability condition. The Swift Language Guide states, "The last argument, *, is required and specifies that on any other platform, the body of the if executes on the minimum deployment target specified by your target."
So, it is correct that on visionOS, your code takes the "if" branch, not the "else" branch.
One solution for you might be conditional compilation (in addition to an availability condition):
private extension View {
func hoverEffect(isEnabled: Bool) -> some View {
#if os(iOS)
if #available(iOS 17.0, *) {
return self
.hoverEffect(.automatic, isEnabled: isEnabled)
} else {
return self
}
#else
return self
#endif
}
}
Best regards,
Greg