Four tips to level up your Swift
How to unwrap optionals in a loop. Utilize @autoclosures, cleaner range checking and easy randomness.
Published: May 10, 2020 Sponsored App StoreSwift has number of advanced features that can help you write more concise and prettier code.
You probably won’t use these daily but when you do, you will be happy that you know them.
case let
to unwrap optionals in for loop
Sometimes you have collection that may contain nil values. Instead of guard or if let inside the loop you can do the following:
for case let item? in items
Note the ? after item. Now you will get only non-nil items and they will be non-optional.
Cleaner range checking
Want to find out whether number falls in particular range? Instead of the usual two ifs and && you can use Range type and its contains method.
Range(min...max).contains(num)
Even neater? Use the tilda operator like so:
min...max ~= num
Easy randomness
Don’t forget, that Swift has so many random
methods. For example you can use Bool.random()
to simulate 50/50 chance. There are same methods on Int
, Double
even CGFloat
.
@autoclosure
This is another of these features you may use once every few months but when you do, you will be glad it is there. What it does? It is basically syntactic sugar to hide closure behind traditional parameter.
Broadly there are two very useful use cases.
- Always getting the current value of value type
- Only using function argument if really needed
Regarding the first use case. I found @autoclosure
helpful when designing data model for table view sections that can have variable number of rows but may not be backed by traditional arrays. If you set model rowCount
with @autoclosure
in your section model, you can change it and it will be reflected automatically on table view reload.
If you were to use just Int
, the inial value would get copied and subsequent changes to your section model would not be reflected in table view.
For the second use case, remember that even if your function takes simple argument like a String
in runtime, this string can be produced by expensive function that may do some heavy work before returning this string.
Logging is good example, because you may wish to log additional information only in debug mode. With @autoclosure
the expensive method mentioned above would be executed only if the method body needed it to log.
func log(_ message: @autoclosure () -> String) {
#if DEBUG
print(message())
#endif
}
Built-in assert
works this way. It only works in debug mode and thanks to its parameters being @autoclosure
nothing expensive can ever get executed in release mode.
Uses: Xcode 12 & Swift 5.3