Revisiting some old style rules with new twists.
The Rule of Lily: “When a trailing closure argument is functional, use parentheses. When it is procedural, use braces.”
myCollection.map({blah}).filter({blah}).etc
myCollection.forEach {} // or
dispatch_after(when, queue) {}
The consistency of style communicates whether closures return values. There’s an ongoing dispute as to whether a space should be left before trailing braces.
The Rule of Self
: “Implicit member expressions enable you to omit self
when the compiler can unambiguously infer member types. Use self
whenever a method call reflexively refers back to an instance.”
Consider the following for-loop’s where
clause. The contains
method call lacks an explicit subject. What is doing the containing? A container isn’t included as method parameter so it has to be the calling instance.
for (flagLessOne, string) in strings.enumerate()
where contains(
Features(rawValue: 1<<(flagLessOne + 1))) {
nameArray.append(string)
}
Fully qualifying the call clarifies the subject ambiguity and vastly improves readability:
for (flagLessOne, string) in strings.enumerate()
where self.contains(
Features(rawValue: 1<<(flagLessOne + 1))) {
nameArray.append(string)
}
The Rule of Conditional Binding Cascades: “Unless you’re mixing var
and let
conditional bindings, use a single if let
or if var
introduction. Add liberal whitespace as needed.”
Instead of:
if let x = x, let y = y, let z = z {blah}
use:
if let x = x, y = y, z = z {blah}
Removing extraneous let
keywords simplifies the binding cascade, and Xcode will nicely co-align these for you:
if let
x = x,
y = y,
z = z {
...blah...
}
Although cascaded bindings avoids the pre-Swift 2 “pyramids of doom”, they tend towards “constipated blocks of horror”. When faced with excess serial bindings, interleave them with spaces and comments, as in the following example, or use a sequence of guard statements.
if let
// Access JSON as dictionary
json = json as? NSDictionary,
// Retrieve results array
resultsList = json["results"] as? NSArray,
// Extract first item
results = resultsList.firstObject as? NSDictionary,
// Extract name and price
name = results["trackName"] as? String,
price = results["price"] as? NSNumber {
// ... blah blah ...
}
The Rule of Pattern Matching Keywords: “When everything’s a binding, unify your bindings.”
Combine multiple pattern matching bindings by moving keywords out of tuples. Instead of:
if case (let x?, let y?) = myOptionalTuple {
print(x, y)
}
Use:
if case let (x?, y?) = myOptionalTuple {
print(x, y)
}
The Rule of isEmpty
: “If you’re testing a collection’s count, you’re probably doing it wrong.” Prefer isEmpty
to count == 0
.
The Rule of Void
: “Use Void
return types, not ()
.” A function returns -> Void
and not -> ()
.
func doThis() -> Void
func notThis() -> ()
The Rule of !: “Every time you use an exclamation point in Swift, a kitten dies.” Wherever possible, avoid forced casts and forced unwrapping.
The Rule of Collection Creation: “Use explicit typing and empty collections.” Types to the left of the assignment, empty instances to the right.
Instead of:
var x = [String: Int]() // and
var y = [Double]()
var z = Set<String>()
var mySet = MyOptionSet()
use
var x: [String: Int] = [:]
var y: [Double] = []
var z: Set<String> = []
var mySet: MyOptionSet = []
Cite.
The “Mike Ash” colon rule: “Space to the right. No space to the left.” Or no soup for you!
Prefer
[key: value] // and
struct Foo: MyProtocol
to
[key : value]
struct Foo : MyProtocol
The Rules of Moving-On-From-Objective-C:
- Don’t add Objective-C-style parentheses around
if
and switch
conditions or with return
keywords.
- Use camel case for allTheConstants and not ALL_CAPS
- Prefer Swift constructors to legacy ones, e.g.
CGPoint(x: 1, y:1)
over CGPointMake(1, 1)
- Avoid terminal semicolons even though they compile. They make you look bad and you should feel bad for using them.
Update: Yes, I don’t just talk the talk, I walk the walk with these rules in my code:

github repo