Understanding Swift Attribute Annotations
A slightly more technical post that some of my usual ones for the mobile developers in my network. We have seen the Swift language grow and become more powerful over the years, compared to it’s humble beginnings.
I have really enjoyed working on some great apps for our clients in recent years, and working with the latest versions of Swift has been very fun, using the latest capabilities of the language. One area that we have seen a lot of evolution is through attribute annotations, that we apply to change the behaviour of functions, classes and properties.
I thought I’d do a quick writeup summarising the main ones that I use in day-to-day iOS Development, as I am sure it has now got to a stage where it might appear a bit intimidating to people who are just starting off their iOS journey!
@escaping is one of the most common attributes that you will see and is worth getting familiar with. In simplest terms - this is applied to to closured that could be called after the function returns. A very common scenario is if you are planning to store the closure in a variable, which will outlive the lifespan of the function. This includes scenarios such as completion handlers that are placed onto a DispatchQueue.
If your closure is executed within the function body itself, then it is non-escaping, and the @escaping attribute is not needed.
领英推荐
@Sendable is one of the newer attributes added to Swift 5.5 and has to do with safe concurrency, and to fully understand requires a level of understanding when it comes to concurrency. One of the biggest benefits of using @Senable is getting compile-time checks that validate your code isn’t capturing any mutable shared state, which could cause your typical sort of threading issues such as data racing conditions, state inconsistencies, and crashes. Its especially helpful when working on shared libraries and frameworks - as it helps communicate to other developers that the closure is safe to use in concurrent environments.
@MainActor was also introduced in Swift 5.5 - and is one of those attributes that you will start seeing very frequently in modern iOS codebases. It has definitely been introduced into the language as a quality of life feature when it comes to working with modern apps, where performing async operations is extremely common. It can be applied at a very granular level - such as against a single function or property, or can be placed against an actual type, such as a class.
It can be easy to be lazy and apply @MainActor to everything - but it should be carefully considered. It is to be used when your type/function/property performs updates to the UI, and as we know UI updates need to be performed on the “main actor” / “main thread” in a single-threaded execution model. Attempting to update the UI from a background thread. Attempting to update the UI from a background thread can result in a variety of problems.
I prefer being granular with my usage of @MainActor - if a specific attribute or function is required to be executed on the main actor. A more fine-grained control to which part of your code is executing on the main actor will lead to overall better performance of your app.
@autoclosure is a nice attribute which can add a bit of syntax sugar to your code in some scenarios. It is most commonly used when you want to defer the actual evaluation of your expression until a later point when its actually needed to be evaluated - which we sometimes refer to as “lazy evaluation”. These situations generally occur when you have a closures as an argument for your function, and you want to make the life easier for those calling the function - by allowing them to pass the expression directly, instead of themselves doing the act of wrapping it in a closure - which makes the syntax cleaner and easier to read in many situations.
iOS/Rust/Go/JS/TS/AWS/etc developer. Dad joke dealer.
1 年Nice one Kris! I do worry a bit that swift has kinda 'gone full java' with annotations... it certainly a big language now. Remember when you had one character: '+' for static, and '-' for instance function, and that was it. But on the other hand, these new annotations really make it much more safe. Super helpful when writing library code. I think in general, this stuff is great :)