Hallo meisjes en jongens, Leo hier. The topic today is how to make APIs constraints in Swift.
It’s a very quick tip on how to turn code unavailable in Swift. It’s very interesting that Xcode helps you when you try to constrain your code to some version or make it unavailable at all.
When you are developing frameworks, for example, you might want to update your network calls to be updated to use async/await news API that only is compatible with iOS 13 or higher. This can be done using the available API.
Let’s code but first…
Painting of The Day
This painting is the “Bowl of Fruit”, an 1857 masterpiece from Henri Fantin-Latour. He was a French painter and lithographer best known for his flower paintings and group portraits of Parisian artists and writers. Although Fantin-Latour befriended several of the young artists who would later be associated with Impressionism, including Whistler and Manet, Fantin’s own work remained conservative in style.
The reason I’ve chosen this piece is that the apple was unavailable in heaven, but Adam and Eve don’t care about the warnings, right?
Problem – How to Make APIs Constraints in Swift
You are developing a framework but need to constrain some part of it to an iOS version or higher. And need to make another part of the code completely unavailable.
Let’s examine the code below:
class ExternalFramework { public func addByTwo(value: Int) -> Int { printTwo() return value + 2 } private func printTwo() { print("2") } }
Very simple code. Just an ExternalFramework class as an example of an external framework and two functions. The first one returns the struct Integer and is public, it’s the framework entry point, and the second just prints “2” in the console.
Let’s constrain the use of function addByTwo to only iOS 15 or higher using an annotation called *available*. See the picture below:
Let’s explore each one of the attributes of the annotation.
Deprecated Attribute of @avaliable
If you want to warn your users that this API is deprecated for iOS 11 or higher you just need to add this:
@available(iOS, deprecated: 11 ) public func addByTwo(value: Int) -> Int { printTwo() return value + 2 }
The result is the caller gets a warning when trying to use the function:
Message attribute of @available
The message attribute you have to use with the deprecated one. To send messages to the ones using the old API that something changed, and how they can be up to date with the changes.
@available(iOS, deprecated: 11, message: "Use at your own risk" ) public func addByTwo(value: Int) -> Int { printTwo() return value + 2 }
The caller gets this warning:
The Introduced attribute of @available
When you want to constraint function usability with @available you need to provide two things basically: the platform and the version that is the minimum supported.
@available(platform name, platform version)
For example, if you want that your function only works in iOS 12 or higher. You can do this:
@available(iOS, introduced: 12) public func addByTwo(value: Int) -> Int { printTwo() return value + 2 }
This way you can limit who can use your function. But what happens if I try to use a method which my iOS version is not compatible with?
Xcode gives to you three alternatives to this.
The first one is to do an #avaliable check:
let externalFramework = ExternalFramework()
if #available(iOS 15, *) {
externalFramework.addByTwo(value: 100)
} else {
// Fallback on earlier versions
}
The second one is to add @available(iOS 15, *) to the method that is the caller of the externalFramework.addByTwo function. This usually doesn’t solve the problem because if you can’t use it inside the function body it’s unlike you will solve your problem by doing this. Anyway, this is useful when building frameworks and you need that all the chain of calls uses the same iOS version constraints.
And finally, the third one is to add @available(iOS 15, *) to the enclosing class. And the reasons to do that are very similar to the case above. You need that every caller has awareness that needs to be in a specific or higher version of iOS.
The Renamed attribute of @available
When you need a framework API to change the name, just add the renamed attribute to a deprecated function like this:
@available(iOS, deprecated: 11, renamed: "addByForSureTwo") public func addByTwo(value: Int) -> Int { printTwo() return value + 2 }
Xcode is very handy when you use this because it already suggests fixing a new method, even if the method doesn’t exist. Weird? Yes. Handy? For sure.
The Unavailable attribute of @available
And the last attribute, if you want don’t want that your users use the API this attribute is for you! You can even show a message to the users.
@available(iOS, unavailable, message: "This API will be discontinued and could not be used anymore") public func addByTwo(value: Int) -> Int { printTwo() return value + 2 }
The user will get this error:
And that’s it! You made your API unavailable and gave a nice message to users!
Summary – How to make APIs Constraints in Swift
It’s always good to know the alternatives to writing great API. A well-documented API can save thousands of development hours and hair too. Today we study all the @available annotation attributes and how this can be useful in your code base, especially if you are writing a cocoa pod, a framework static or not, etc.
That’s all my people, I hope you liked reading this article as much as I enjoyed writing it. If you want to support this blog you can Buy Me a Coffee or leave a comment saying hello. You can also sponsor posts and I’m open to freelance writing!
You can reach me on LinkedIn or Twitter and send me an e-mail through the contact page.
Thanks for reading and… That’s all folks.
Credits: