How to handle API Changes with @available

⋅ 3 min read ⋅ Swift

Table of Contents

In the previous post, How to handle API Changes with #available, we learn a Swift tool to live with changes. But #available alone can't handle all the cases for API changes. We also need an @available attribute.

What is an @available attribute

In Swift, there is another tool that helps you cope with API changes, the @available attribute.

An @available attribute provides additional information about the declaration. We apply this attribute to limit the usage of a declaration to certain Swift versions or certain platform versions.

Here is an example of marking a function to work only on iOS 15 forward.

@available(iOS 15.0, *)
func addButton() {
var configuration = UIButton.Configuration.filled()
configuration.title = "Click Me"
let button = UIButton(configuration: configuration)
view.addSubview(button)
}

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

How to use an @available attribute

The available attribute is a declaration attribute, that's means you can apply it to any declaration, e.g., class declaration or method declaration.

The available attributes have the following form:

@available(platform name version number, ..., *)
// class platformSpecificClass {}
// func platformSpeficMethod() {}

We provide a list of comma-separated platforms and versions that you want and end with an asterisk (*). You can check out all available platforms here.

Why do we need an @available attribute

As you can see, the main function of the available attribute seems to be on the API creator side, where you can limit class or function declaration to a specific platform version.

How can this tool help us to handle changes?

The type of change that we usually need available attribute is a change that introduce a new approach to the system. This kind of change usually causes us to have two sets of implementation, one for the new flow and one for the old approach.

It is easier to understand with an example.

SceneDelegate

When Apple adds support for multiple windows in iOS 13, it dramatically changes its entire app life cycle. We have a new method in UIApplicationDelegate and a new UISceneDelegate protocol.

SceneDelegate can't live in an old iOS version but is required in a new one. Availability condition can't help you on this since statements are not allowed at the top level.

We can't do something like this with #available.

if #available(iOS 13, *) {
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// ...
}
}

But we can do that with the available attribute.

@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// ...
}

An available attribute also helps in a case where a new approach and an old one need to co-exist, like in AppDelegate where we can scope usage of some delegate method to a specific platform version.

We can do something like this if we want to listen to the UISceneSession lifecycle.

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// MARK: UISceneSession Lifecycle
@available(iOS 13.0, *)
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

@available(iOS 13.0, *)
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {}
}

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

Conclusion

The available attribute (@available) has broader functionality than the availability condition (#available). I sit far more to the side of the API creator, but as you can see, it also benefits on an API consumer side.

In a future post, I will explore the full potential of @available and how it can benefit API creators.


Read more article about Swift or see all available topic

Enjoy the read?

If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Buy me a coffee Tweet Share
Previous
How to create observable variables from other observable variables in GetX

Learn how to make derived variables observable in GetX.

Next
How to prepare your iOS project to support modular architecture

At the beginning of a project, there are a lot of changes and uncertainty. You might want to start modularizing your code in the later phase, where the scope is clearer. Let's see how to prepare your single module project to support future modularizing.

← Home