Holy Swift

Holy Swift

How to do APIs constraints with @Available in Swift

How to do APIs constraints with @Available in Swift

The well-build framework API

Subscribe to my newsletter and never miss my upcoming articles

Hallo meisjes en jongens, Leo hier.

Today it's a very quick tip to how to turn code unavaliable in Swift. It's very interesting that Xcode help you when you try to constraint 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 are compatible with iOS 15 or higher. This can be done using the available API.

Let's code but first...

The Painting

This painting is the "Bowl of Fruit", 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 apple was unavailable in heaven, but Adam and Eve don't care about the warnings, right?

Problem

You are developing a framework but need to constraint 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 example of 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 print "2" in the console.

Let's constraint the use of function addByTwo to only iOS 15 or higher using annotation called available. See the picture below:

Screenshot 2021-08-05 at 08.30.45.png

Let's explore each one of the annotations attributes.

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 try to use the function:

Screenshot 2021-08-05 at 08.51.57.png

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 get this warning:

Screenshot 2021-08-05 at 08.55.42.png

Introduced attribute of @available

When you want to constraint a 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 that my iOS version is not compatible?

Screenshot 2021-08-05 at 08.37.37.png

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 add @ available(iOS 15, *) to the method that is caller of the externalFramework.addByTwo function. This usually don't solve the problem because if you can't use inside the function body it's unlike you will solve your problem doing this. Anyway this is useful when building frameworks and you need that all the chain of calls use the same iOS version constraints.

And finally the third one is add @available(iOS 15, *) to the enclosing class. And the reasons to do that are very similar the case above. You need that every caller have awareness that need to be in a specific or higher version of iOS.

Renamed attribute of @available

When you need to an framework API to change 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 suggest to fix to new method, even if the method don't exists. Weird yes, handy for sure.

Screenshot 2021-08-05 at 09.04.00.png

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 supported and could not be used anymore")
    public func addByTwo(value: Int) -> Int {
        printTwo()
        return value + 2
    }

The user will get this error:

Screenshot 2021-08-05 at 09.17.15.png

And that's it! You made your api unavailable and gave a nice message to users!

Conclusion

It's always good to know the alternatives to write great API. A well documented API can save thousand of development hours and hairs too. Today we study all the @available annotation attributes and how this can be useful in your code base, specially if you are writing an cocoa pod, a framework static or not etc.

That's all my people, I hope you liked this as I liked writing. If you want to support this blog you can Buy Me a Coffee or just leave a comment saying hello.

Thanks for the reading and... That's all folks.

credits: image

Interested in reading more such articles from Leonardo Maia Pugliese?

Support the author by donating an amount of your choice.

 
Share this