Backporting SwiftUI APIs
I can improve the process of removing backwards compatibility shims by using conditional compilation to remind me when they’re no longer necessary!
[…]
This does mean that the first time we change our deployment target, we’ll get a bunch of compilation errors. But given the nature of how
Backportis implemented, this should be a relatively quick process to move past. (And of course, you’re welcome to use#warninginstead of#error).
SwiftUIBackports mirrors Apple’s SwiftUI API names, shapes, behavior, documentation, and availability where practical. This keeps app code familiar today, and easy to migrate away from once your deployment target reaches the native API.
Backports are discovered through
.backport, theBackportnamespace, orbackport-prefixed environment values.
Usually, we don’t see many new APIs in intermediate releases like 27.1, but this time is different. Apple introduced several new iPhone Duo-related APIs in the 27.1 release. This week, we will learn how to use all of these new APIs without bumping your project’s target version.
[…]
Here we introduced the
toolbarVerticalBehaviorfunction on theBackporttype that handles availability checks and calls the new APIs if available or returns a plain view when it is not available.
Previously:
- Developing for iPhone Duo
- SwiftUI Toolbars
- SwiftUI in appleOS 27
- Simplifying Backwards Compatibility in Swift
2 Comments RSS · Twitter · Mastodon
I don't get the advantage of using the Backport namespace. Is there any downside to shadowing the actual modifier with @_disfavoredOverload and calling back to the official API where supported?
Here's an example. If you wanted to, you could also emit a warning, if no longer necessary with the method from Dave. Once no longer necessary, I only need to remove the function and don't have to touch any call-site.
extension View {
@_disfavoredOverload @ViewBuilder
func safeAreaPadding(_ edges: Edge.Set = .all, _ length: CGFloat? = nil) -> some View {
if #available(iOS 17, *) {
safeAreaPadding(edges, length)
} else {
safeAreaPaddingBackport(edges, length)
}
}
}
@Melvin I’m not sure, but does your way only work if the extension is defined in the same target as where it’s called?