A guide to Swift coding style and guidelines.
Software (a.k.a. source code) has a number of interesting characteristics -
- It is written once but read many times.
- It is harder to read than it is to write.
- The main consumer is not the compiler but people.
- Well written software not only satisfies the compiler (i.e. no errors or warnings) and correctly implements the desired feature set, but it’s also easy to consume in a relatively short period by a software engineer with the proper background.
The objective of the this guide is to encourage patterns that accomplish the following goals:
- Increase rigor, and decreased likelihood of programmer error.
- Increase clarity of intent.
- Reduce verbosity.
- Maintainability. Robustness.
Where the guide is silent, default to Apple's coding guidelines for Cocoa.
- Naming
- Code Organization
- Comments
- Mutability-Immutability
- Types
- Optionals
- Closures
- Classes and Structures
- Singletons
- Semicolons
- Miscellaneous
Names should be meaningful and compact, written in camelCase. Try to ask yourself whether the name of a type sufficiently explains its behavior. Meaningful naming is very important to other developers because they define some expectations about their own roles.
- Always use meaningful english names that are self-descriptive.
- Always start names of classes, structs, typealias and enumerations with an uppercase letter.
- Always start names of variables, functions, and methods with a lowercase letter.
- Abbreviations should be avoided, except where they are widely accepted (e.g. fileURL)
- Never create similar names. In particular, do not create names that differ only by case.
- Never use identifiers that begin with an underscore; these are reserved by Apple.
- Never use single or simple character names (e.g., "j", "iii") except for local loop and array indices.
- As far as possible, try not to name your classes ending with words like
Manager
,Helper
orUtility
because their meanings are very generic and their role can be easily misinterpreted. We tend to dump a lot of code to such classes.
For functions and init methods, prefer named parameters for all arguments unless the context is very clear. Include external parameter names if it makes function calls more readable.
func dateFromString(dateString: String) -> NSDate
func convertPointAt(column column: Int, row: Int) -> CGPoint
func timedAction(afterDelay delay: NSTimeInterval, perform action: SKAction) -> SKAction!
// would be called like this:
dateFromString("2014-03-14")
convertPointAt(column: 42, row: 13)
timedAction(afterDelay: 1.0, perform: someOtherAction)
Swift types are automatically namespaced by the module that contains them and you need not add a class prefix.
Source files should have the following kind of organization.
import StarWarsKit
class JediTemple {
//MARK: Public properties
let jediKnights: [Jedi]
private(set) var force: Force
//MARK: Private properties
private let aliveKnights: [Jedi]
//MARK: Init
init(jedi: [Jedi], force: Force)
//MARK: Public methods
func calcTotalForce()
//MARK: Private methods
private func councilMembers() -> [Jedi]
}
//MARK: SomeProtocol methods
extension JediTemple: Printable {
var dialogue: String {
return "Fight, together we must!"
}
}
In general, code should be self-documenting as much as possible. However, there are behaviors that cannot be statically expressed within code and can only be determined at runtime. Under these circumstances, comments should be provided to explain why a particular piece of code does something. All comments must be kept up-to-date or deleted.
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.
-
A
let
-binding guarantees and clearly signals to the programmer that its value will never change. Subsequent code can thus make stronger assumptions about its usage. -
It becomes easier to reason about code. Had you used
var
while still making the assumption that the value never changed, you would have to manually check that. -
A good technique is to define everything using
let
and only change it tovar
if the compiler complains. -
let
also allows the compiler to make optimizations.
Use native Swift types before you come up with your own. Every type can be extended, so sometimes instead of introducing new types, it's convenient to extend or alias existing ones.
Remember that Objective-C classes that have native Swift equivalents are not automatically bridged, e.g. NSString
is not implicitly bridged to String
in the following example.
func lowercase(string: String) -> String
let string: NSString = /* ... */
lowercase(string) // compile error
lowercase(string as String) // no error
Types should be inferred whenever possible. Don't duplicate type identifier if it can be resolved in compile time:
// preferred
let name = "Anakin Skywalker"
let planets = [.Tatooine, .Coruscant]
let colors = ["red": 0xff0000, "green": 0x00ff00]
// not preferred
let name: String = "Padmé"
let planets: [Planet] = [.Naboo, .Coruscant]
let colors: [String: UInt32] = ["blue": 0x0000ff, "white": 0xffffff]
Also, associate colon with type identifier.
// preferred
class VideoArticle: Article
let events: [Timestamp: Event]
// not preferred
class VideoArticle : Article
let events : [Timestamp : Event]
Declare variables and function return types as optional with ?
where a nil
value is acceptable.
If you have an identifier foo
of type FooType?
, don't force-unwrap (foo!
) it to get to the underlying value. Force unwrapping is more prone to lead to runtime crashes.
Instead, use Optional Binding to safely unwrap the value:
if let foo = foo {
// Use unwrapped `foo` value in here
} else {
// If appropriate, handle the case where the optional is nil
}
Unwrapping several optionals in nested if-let statements is forbidden, as it leads to "pyramid of doom". Swift allows you to unwrap multiple optionals in one statement.
let name: String?
let age: Int?
if let name = name, age = age where age >= 13 {
/* ... */
}
Or use guard
statements
guard let modelURL = NSBundle.mainBundle().URLForResource(modelName, withExtension:"momd") else {
fatalError("Error loading model from bundle")
}
guard let managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL) else {
fatalError("Error initializing mom from: \(modelURL)")
}
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
You might want to use Swift's Optional Chaining in some of these cases, such as:
// Call the function if `foo` is not nil. If `foo` is nil, ignore we ever tried to make the call
foo?.callSomethingIfFooIsNotNil()
Wherever possible, use let foo: FooType?
instead of let foo: FooType!
.
Use implicitly unwrapped types only for instance variables that you know will be initialized later before use, such as subviews that will be set up in viewDidLoad.
If the last argument of a function is a closure, use trailing closure syntax.
Trailing closure syntax should be used if a function accepts a closure as its last argument. If it's its only argument, parentheses may be ommited. Unused closure arguments should be replaced with _
(or fully ommited if no arguments are used). Argument types should be inferred.
func executeRequest<T>(request: Request<T>, completion: (T, Error?) -> Void)
executeRequest(someRequest) { (result, _) in /* ... */ }
Use implicit return
in one-line closures with clear context.
let numbers = [1, 2, 3, 4, 5]
let even = filter(numbers) { $0 % 2 == 0 }
Remember, structs have value semantics. Use structs for things that do not have an identity. An array that contains [a, b, c] is really the same as another array that contains [a, b, c] and they are completely interchangeable. It doesn't matter whether you use the first array or the second, because they represent the exact same thing. That's why arrays are structs.
Classes have reference semantics. Use classes for things that do have an identity or a specific life cycle. You would model a person as a class because two person objects are two different things. Just because two people have the same name and birthdate, doesn't mean they are the same person. But the person's birthdate would be a struct because a date of 3 March 1950 is the same as any other date object for 3 March 1950. The date itself doesn't have an identity.
Value types are great for representing data in the app. Reference types are great to represent behavior in the app.
Note that inheritance is (by itself) usually not a good reason to use classes, because polymorphism can be provided by protocols, and implementation reuse can be provided through composition.
For example, this class hierarchy:
class Vehicle {
let name: String
let numberOfWheels: Int
init(numberOfWheels: Int) {
self.numberOfWheels = numberOfWheels
}
func description() -> String {
return "The vehicle is a \(name) which runs on \(numberOfWheels) wheels."
}
}
class Bicycle: Vehicle {
init() {
super.init(numberOfWheels: 2)
}
}
class Car: Vehicle {
init() {
super.init(numberOfWheels: 4)
}
}
could be refactored into these definitions:
protocol Vehicle {
var numberOfWheels: Int { get }
var name: String { get}
func description() -> String
}
struct Bicycle: Vehicle {
let name = "Bicycle"
let numberOfWheels = 2
}
struct Car: Vehicle {
let name = "Car"
let numberOfWheels = 4
}
extension Vehicle {
func description() -> String {
return "The vehicle is a \(name) which runs on \(numberOfWheels) wheels."
}
}
For conciseness, avoid using self
since Swift does not require it to access an object's properties or invoke its methods.
Use self
when required to differentiate between property names and arguments in initializers, and when referencing properties in closure expressions (as required by the compiler):
class BoardLocation {
let row: Int, column: Int
init(row: Int, column: Int) {
self.row = row
self.column = column
let closure = {
println(self.row)
}
}
}
When adding protocol conformance to a class, prefer adding a separate class 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.
Also, don't forget the // MARK:
comment to keep things well-organized!
Preferred :
class MyViewcontroller: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewcontroller: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewcontroller: UIScrollViewDelegate {
// scroll view delegate methods
}
Not Preferred :
class MyViewcontroller: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
// all methods
}
Use the native Swift struct initializers rather than the legacy constructors.
Preferred:
let bounds = CGRect(x: 40, y: 20, width: 120, height: 80)
let centerPoint = CGPoint(x: 96, y: 42)
Not Preferred:
let bounds = CGRectMake(40, 20, 120, 80)
let centerPoint = CGPointMake(96, 42)
Prefer the struct-scope constants CGRect.infinite
, CGRect.null
, etc. over global constants CGRectInfinite
, CGRectNull
, etc. For existing variables, you can use the shorter .zero
.
Mark the init
method as private
. This prevents others from using the default '()' initializer for the class.
final class Analytics {
static let sharedInstance = Analytics()
private init() {}
}
Also, there is no need to wrap it inside dispatch_once
for thread-safety or concurrency concers. Quoting from Apple's blog -
The lazy initializer for a global variable (also for static members of structs and enums) is run the first time that global is accessed, and is launched as
dispatch_once
to make sure that the initialization is atomic. This enables a cool way to usedispatch_once
in your code: just declare a global variable with an initializer and mark it private.
That said, use of singletons can be exploited.
'Wisely use them, you must!'
Swift does not require a semicolon after each statement in your code. They are only required if you wish to combine multiple statements on a single line.
Do not write multiple statements on a single line separated with semicolons.
The only exception to this rule is the for-conditional-increment
construct, which requires semicolons. However, alternative for-in
constructs should be used where possible.
- All methods and functions shall have a single exit point. Exceptions if you're using
guard
statements. - Do not use numeric values or strings (i.e., Magic numbers); use symbolic values instead.
- Declare each variable with the smallest possible scope and initialize it at the same time.
- Don't commit code that will never execute; just delete it. This applies to:
- Methods that are never called.
- Commented-out code
- Don't commit code that serves no purpose. This applies to:
- Code automatically generated by Xcode that does nothing except call
super
- Code automatically generated by Xcode that does nothing except call
This guide is inspired (shamelessly-taken-from) these sources -
- The Official raywenderlich.com Swift Style Guide
- Github Swift Style Guide
- A little help from @darcwader, @peculiar.
If you have any suggestions, feel free to send a pull request.