Swift Coding Conventions
Collection of some Swift coding conventions, which will make Swift code more maintainable, more readable.
The following is conventions I like or I will likely misuse. For a complete version, go to:
Naming
Descriptive and consistent naming makes software easier to read and understand. Use the Swift naming conventions described in the API Design Guidelines. Some key principles include:
- prioritizing clarity over brevity
- striving for fluent usage
- using uppercase for types (and protocols), lowercase for everything else
- boolean types should read like assertions
- choosing good parameter names that serve as documentation
- generally avoiding abbreviations
- taking advantage of default parameters
- labeling closure and tuple parameters
- verb methods follow the -ed, -ing rule for the non-mutating version
- noun methods follow the formX rule for the mutating version
- protocols that describe what something is should read as nouns
- protocols that describe a capability should end in -able or -ible
- striving for clarity at the call site
Try to Form Grammatical English Phrases
Preferred:
1 2 3 |
|
Not Preferred:
1 2 3 |
|
Mutating/Nonmutating Methods Naming
When the operation is naturally described by a verb, use the verb’s imperative for the mutating method and apply the “ed” or “ing” suffix to name its nonmutating counterpart.
Mutating | Nonmutating |
---|---|
x.sort() |
z = x.sorted() |
x.append(y) |
z = x.appending(y) |
When the operation is naturally described by a noun, use the noun for the nonmutating method and apply the “form” prefix to name its mutating counterpart.
Nonmutating | Mutating |
---|---|
x = y.union(z) |
y.formUnion(z) |
j = c.successor(i) |
c.formSuccessor(&i) |
Boolean Methods Naming
Uses of Boolean methods and properties should read as assertions about the receiver when the use is nonmutating, e.g. x.isEmpty
, line1.intersects(line2)
.
Protocol Naming
Protocols that describe what something is should read as nouns (e.g. Collection
).
Protocols that describe a capability should be named using the suffixes -able, -ible, or -ing (e.g. Equatable
, ProgressReporting
).
Avoid Abbreviations
The intended meaning for any abbreviation you use should be easily found by a web search.
Delegates
When creating custom delegate methods, an unnamed first parameter should be the delegate source. (UIKit contains numerous examples of this.)
Preferred:
1 2 |
|
Not Preferred:
1 2 |
|
Code Organization
Use extensions to organize your code into logical blocks of functionality. Each extension should be set off with a // MARK: - comment
to keep things well-organized.
Protocol Conformance
In particular, when adding protocol conformance to a model, prefer adding a separate extension for the protocol methods. This keeps the related methods grouped together with the protocol and can simplify instructions to add a protocol to a class with its associated methods.
Preferred:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Not Preferred:
1 2 3 |
|
For UIKit view controllers, consider grouping lifecycle, custom accessors, and IBAction in separate class extensions.
Classes and Structures
Use of Self
For conciseness, avoid using self
since Swift does not require it to access an object’s properties or invoke its methods.
Use self
only when required by the compiler (in @escaping
closures, or in initializers to disambiguate properties from arguments). In other words, if it compiles without self
then omit it.
Constants
Constants are defined using the let
keyword, and variables with the var
keyword. Always use let
instead of var
if the value of the variable will not change.
Tip: A good technique is to define everything using
let
and only change it tovar
if the compiler complains!
You can define constants on a type rather than on an instance of that type using type properties. To declare a type property as a constant simply use static let
. Type properties declared in this way are generally preferred over global constants because they are easier to distinguish from instance properties.
Preferred:
1 2 3 4 5 6 |
|
Not Preferred:
1 2 3 4 |
|
Control Flow
Golden Path
When coding with conditionals, the left-hand margin of the code should be the “golden” or “happy” path. That is, don’t nest if
statements. Multiple return statements are OK. The guard
statement is built for this.
Preferred:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Not Preferred:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
When multiple optionals are unwrapped either with guard
or if let
, minimize nesting by using the compound version when possible. Example:
Preferred:
1 2 3 4 5 6 |
|
Not Preferred:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Failing Guards
guard
statements are required to exit in some way. Generally, this should be simple one line statement such as return
, throw
, break
, continue
, and fatalError()
. Large code blocks should be avoided. If cleanup code is required for multiple exit points, consider using a defer
block to avoid cleanup code duplication.
Argument Labels
- Good practice
1 2 |
|
Omit all labels when arguments can’t be usefully distinguished, e.g.
min(number1, number2)
,zip(sequence1, sequence2)
.When the first argument forms part of a prepositional phrase, give it an argument label. The argument label should normally begin at the preposition, e.g.
x.removeBoxes(havingLength: 12)
.- An exception for the principle above arises when the first two arguments represent parts of a single abstraction. In such cases, begin the argument label after the preposition, to keep the abstraction clear.
Preferred:
1 2 |
|
Not Preferred:
1 2 |
|