Swift Style Guide: April 2016 Update
We’ve updated our popular Swift Style Guide for Swift 2.2 – check out the changes inside! By Ray Fix.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Swift Style Guide: April 2016 Update
10 mins
Good news – we have updated our popular Swift Style Guide for Swift 2.2!
Here at raywenderlich.com, we want to have a consistent style for you in our tutorials, books, videos, and conference materials. We believe it improves readability, and makes our content easier and quicker to understand.
At the same time, we want to avoid making a style guide so strict that an author feels like they are wearing a straight-jacket!
We’ve tried our best to walk this line carefully, and you may even wish to adopt some of these standards in your own projects. That said, our style guide is different than other style guides; we’re a tutorial site, which means our priorities are making our code easily readable in printed books and on the web. Many of the decisions are made with an eye toward conserving space for print, legibility, and tutorial writing.
Since our last major style update in April 2015, readers and team members opened dozens of issues against the guide and generated long threads of discussion suggesting how things could be made better. While we could not adopt all of the suggestions, we are truly grateful for feedback and the thoughts it generated. We hope you find this to be a compelling update.
Let’s look at some of the highlights.
Crush the Warnings
In a way, the Swift evolution community sets its own minimal style guidelines by causing the compiler to emit warnings on deprecated language features. You should consider warnings to be errors and fix them.
I am always surprised when I jump on a new project and find that the previous developer didn’t take the time to fix the warnings. We all have deadlines, but don’t let this be you. :]
Swift 2.2 brought several deprecations. For example, the ++
and --
operators along with along with the C-style for-loop are slated for removal in Swift 3. Rather than falling back to using a while-loop, go ahead and use enumerate()
or the full power of ranges. It’s easy and fun. For example:
// list the index and item
for (index, item) in items.enumerate() {
print("\(index): \(item)")
}
// count up from zero up to items.count by twos
for index in 0.stride(to: items.count, by: 2) {
print(index)
}
// count down from three to zero
for index in (0...3).reverse() {
print(index)
}
Another deprecation includes using strings instead of the new #selector
expression. Xcode’s “fix it” button helps you out here, but it always uses the fully qualified names. Usually you can take advantage of context to make it shorter and more readable. Make the extra effort.
Mind the Golden Path
The Golden Path (or sometimes Happy Path) rule dates back to our Obj-C style guide. It refers to the notion that you don’t want to nest conditional statements too deeply. That quickly gets hard to read.
// Not preferred
func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {
if let context = context {
if let inputData = inputData {
// use context and input to compute the frequencies
return frequencies
}
else {
throw FFTError.NoInputData
}
}
else {
throw FFTError.NoContext
}
}
If you can help it, don’t nest at all. Embrace the concept of the early exit.
Every major release of Swift: 1.0 with optional chaining, 1.2 with multiple let
optional binding and 2.0 with the guard
, throws
and defer
statements have given you increasingly better tools to build a clean, readable golden paths through your methods. Use them!
// Preferred
func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {
guard let context = context else { throw FFTError.NoContext }
guard let inputData = inputData else { throw FFTError.NoInputData }
// use context and input to compute the frequencies
return frequencies
}
Advantages of Being Lazy
Swift is a “safe” language. This means, among other things, that your objects are always guaranteed to be fully initialized before you use them. The rules can sometimes get a bit tricky. In fact, you might want to consult out our Swift Initialization in Depth tutorial if you want to understand the finer points of the process.
With UIViewControllers
, full initialization is often delayed until the views load. Lazy initialization is a handy (and often safer) approach to use.
Consider the following stored property in your view controller:
lazy var locationManager: CLLocationManager = {
let manager = CLLocationManager()
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.delegate = self
manager.requestAlwaysAuthorization()
return manager
}()
This allows you to defer initialization until you actually refer to the stored property which might have side-effects such as a permissions popup to appear.
Lifetime Extension
When you are dealing with asynchronous requests such as a network call and then use that data to update your UI it is easy to inadvertently create a retain cycle. (Heap leak!)
Swift cleverly makes you explicitly type out self
to clue you in that you might be doing this. Swift also lets you supply a capture list to break the retain cycle.
Be very careful using [unowned self]
in your capture list. If your UI doesn’t outlive your network request, you just created an asynchronous crasher. Instead, prefer the more bulletproof [weak self]
.
In your closure, rather than optionally unwrap self each time, extend lifetime by performing the so-called strong-weak dance. This results in fewer possible code paths so is more obviously correct. An example of the canonical strong-weak dance is:
resource.request().onComplete { [weak self] response in
guard let strongSelf = self else { return }
let model = strongSelf.updateModel(response)
strongSelf.updateUI(model)
}
We converged on the constant name strongSelf
by looking at what a few successful open source projects (such as Alamofire) were doing. Perhaps in the future there will be a language feature to help minimize this boilerplate. For now, extending lifetime using the strong-weak dance ensures that you don’t create a retain cycle and that you don’t crash.