The overarching goals are conciseness, readability, and simplicity.
Use descriptive names with camel case for classes, methods, variables, etc.
- Class, struct and enum names should start with a upper case letter
- Method and variables names should start with a lower case letter
Preferred:
private let maximumWidgetCount = 100
class WidgetContainer {
var widgetButton: UIButton
let widgetHeightPercentage = 0.85
}
Not Preferred:
let MAX_WIDGET_COUNT = 100
class app_widgetContainer {
var wBut: UIButton
let wHeightPct = 0.85
}
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(delay delay: NSTimeInterval, perform action: SKAction) -> SKAction!
// would be called like this:
dateFromString("2014-03-14")
convertPointAt(column: 42, row: 13)
timedAction(delay: 1.0, perform: someOtherAction)
For methods, follow the standard Apple convention of referring to the first parameter in the method name:
class Guideline {
func combineWithString(incoming: String, options: Dictionary?) { ... }
func upvoteBy(amount: Int) { ... }
}
Use UpperCamelCase for enumeration values:
enum Shape {
case Rectangle
case Square
case Triangle
case Circle
}
Swift types are automatically namespaced by the module that contains them and you should not add a class prefix. If two names from different modules collide you can disambiguate by prefixing the type name with the module name.
// Both MyModule and SomeModule contain UsefulClass
import SomeModule
let myClass = MyModule.UsefulClass()
-
Indent using 4 spaces rather than tabs to conserve space and help prevent line wrapping.
-
Method braces and other braces (
if
/else
/switch
/while
etc.) always open on the same line as the statement but close on a new line. -
Tip: You can re-indent by selecting some code (or ⌘A to select all) and then Control-I (or Editor\Structure\Re-Indent in the menu). Some of the Xcode template code will have 4-space tabs hard coded, so this is a good way to fix that.
Preferred:
if user.isHappy {
// Do something
} else {
// Do something else
}
Not Preferred:
if user.isHappy
{
// Do something
}
else {
// Do something else
}
- There should be exactly one blank line between methods to aid in visual clarity and organization. New line within methods should separate functionality, but having too many sections in a method often means you should refactor into several methods.
- End files with a newline.
- Make liberal use of vertical whitespace to divide code into logical chunks.
- Don’t leave trailing whitespace. (Except on blank lines to keep the indentation level)
- Trust Xcode default re-indentation
When they are needed, use comments to explain why a particular piece of code does something. Comments must be kept up-to-date or deleted.
Avoid block comments inline with code, as the code should be as self-documenting as possible. Exception: This does not apply to those comments used to generate documentation.
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.
Sometimes, things should be structs but need to conform to AnyObject
or are historically modeled as classes already (NSDate
, NSSet
). Try to follow these guidelines as closely as possible.
Unless you require functionality that can only be provided by a class (like identity or deinitializers), implement a struct instead.
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 numberOfWheels: Int
init(numberOfWheels: Int) {
self.numberOfWheels = numberOfWheels
}
func maximumTotalTirePressure(pressurePerWheel: Float) -> Float {
return pressurePerWheel * Float(numberOfWheels)
}
}
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 }
}
func maximumTotalTirePressure(vehicle: Vehicle, pressurePerWheel: Float) -> Float {
return pressurePerWheel * Float(vehicle.numberOfWheels)
}
struct Bicycle: Vehicle {
let numberOfWheels = 2
}
struct Car: Vehicle {
let numberOfWheels = 4
}
Rationale: Value types are simpler, easier to reason about, and behave as expected with the let
keyword.
Classes should start as final
, and only be changed to allow subclassing if a valid need for inheritance has been identified. Even in that case, as many definitions as possible within the class should be final
as well, following the same rules.
Rationale: Composition is usually preferable to inheritance, and opting in to inheritance hopefully means that more thought will be put into the decision.
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, it is recommended to add // 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: - UITableViewDelegate
extension MyViewcontroller: UITableViewDelegate {
// table view delegate methods
}
Not Preferred:
class MyViewcontroller: UIViewController, UITableViewDataSource, UITableViewDelegate {
// all methods
}
When accessing properties or methods on self
, alway use self
this way the developper knows that he is using instance properties/method:
private class History {
var events: [Event]
func rewrite() {
self.events = []
}
}
When possible, omit the get
keyword on read-only computed properties and
read-only subscripts.
So, write these:
var myGreatProperty: Int {
return 4
}
subscript(index: Int) -> T {
return objects[index]
}
… not these:
var myGreatProperty: Int {
get {
return 4
}
}
subscript(index: Int) -> T {
get {
return objects[index]
}
}
Rationale: The intent and meaning of the first version is clear, and results in less code.
Methods of parameterized types can omit type parameters on the receiving type when they’re identical to the receiver’s. For example:
struct Composite<T> {
…
func compose(other: Composite<T>) -> Composite<T> {
return Composite<T>(self, other)
}
}
could be rendered as:
struct Composite<T> {
…
func compose(other: Composite) -> Composite {
return Composite(self, other)
}
}
Keep short function declarations on one line including the opening brace:
func reticulateSplines(spline: [Double]) -> Bool {
// reticulate code goes here
}
For functions with long signatures, add line breaks at appropriate points and add an extra indent on subsequent lines:
func reticulateSplines(spline: [Double],
adjustmentFactor: Double,
translateConstant: Int,
comment: String) -> Bool {
// reticulate code goes here
}
If your function is bigger, split it in smaller functions
Use trailing closure syntax only if there's a single closure expression parameter at the end of the argument list. Give the closure parameters descriptive names.
Preferred:
UIView.animateWithDuration(1.0) {
self.myView.alpha = 0
}
UIView.animateWithDuration(1.0,
animations: {
self.myView.alpha = 0
},
completion: { finished in
self.myView.removeFromSuperview()
}
)
Not Preferred:
UIView.animateWithDuration(1.0, animations: {
self.myView.alpha = 0
})
UIView.animateWithDuration(1.0,
animations: {
self.myView.alpha = 0
}) { f in
self.myView.removeFromSuperview()
}
For single-expression closures where the context is clear, use implicit returns:
attendeeList.sort { a, b in
a > b
}
Always use Swift's native types when available. Swift offers bridging to Objective-C so you can still use the full set of methods as needed.
Preferred:
let width = 120.0 // Double
let widthString = (width as NSNumber).stringValue // String
Not Preferred:
let width: NSNumber = 120.0 // NSNumber
let widthString: NSString = width.stringValue // NSString
In Sprite Kit code, use CGFloat
if it makes the code more succinct by avoiding too many conversions.
Prefer compact code and let the compiler infer the type for a constant or variable, unless you need a specific type other than the default such as CGFloat
or Int16
.
Preferred:
let message = "Click the button"
let currentBounds = computeViewBounds()
var names = [String]()
let maximumWidth: CGFloat = 106.5
Not Preferred:
let message: String = "Click the button"
let currentBounds: CGRect = computeViewBounds()
var names: [String] = []
NOTE: Following this guideline means picking descriptive names is even more important than before.
Use let foo = …
over var foo = …
wherever possible (and when in doubt). Only use var
if you absolutely have to (i.e. you know that the value might change, e.g. when using the weak
storage modifier).
Rationale: The intent and meaning of both keywords is clear, but let-by-default results in safer and clearer code.
A let
-binding guarantees and clearly signals to the programmer that its value is supposed to and 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.
Accordingly, whenever you see a var
identifier being used, assume that it will change and ask yourself why.
If you have an identifier foo
of type FooType?
or FooType!
, don't force-unwrap it to get to the underlying value (foo!
) if possible.
Instead, prefer this:
if let foo = foo {
// Use unwrapped `foo` value in here
} else {
// If appropriate, handle the case where the optional is nil
}
Alternatively, 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()
Rationale: Explicit if let
-binding of optionals results in safer code. Force unwrapping is more prone to lead to runtime crashes.
Where possible, use let foo: FooType?
instead of let foo: FooType!
if foo
may be nil (Note that in general, ?
can be used instead of !
).
Rationale: Explicit optionals result in safer code. Implicitly unwrapped optionals have the potential of crashing at runtime.
When naming optional variables and properties, avoid naming them like optionalString
or maybeView
since their optional-ness is already in the type declaration.
For optional binding, shadow the original name when appropriate rather than using names like unwrappedView
or actualLabel
.
Preferred:
var subview: UIView?
var volume: Double?
// later on...
if let subview = subview, volume = volume {
// do something with unwrapped subview and volume
}
Prefered
guard let value = opt else { return error }
// continue code
Not Prefered
if let value = opt {
// very long if block
} else {
return error
}
Use the native Swift struct initializers rather than the legacy CGGeometry 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.infiniteRect
, CGRect.nullRect
, etc. over global constants CGRectInfinite
, CGRectNull
, etc. For existing variables, you can use the shorter .zeroRect
.
Prefer the shortcut versions of type declarations over the full generics syntax.
Preferred:
var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?
Not Preferred:
var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>
Prefer the for-in
style of for
loop over the for-condition-increment
style.
Preferred:
for _ in 0..<3 {
println("Hello three times")
}
for (index, person) in enumerate(attendeeList) {
println("\(person) is at position #\(index)")
}
Not Preferred:
for var i = 0; i < 3; i++ {
println("Hello three times")
}
for var i = 0; i < attendeeList.count; i++ {
let person = attendeeList[i]
println("\(person) is at position #\(i)")
}
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.
Preferred:
let swift = "not a scripting language"
Not Preferred:
let swift = "not a scripting language";
NOTE: Swift is very different to JavaScript, where omitting semicolons is generally considered unsafe
- Use private by default, internal when needed and public with precaution
Top-level functions, types, and variables should always have explicit access control specifiers:
public var whoopsGlobalState: Int
internal struct TheFez {}
private func doTheThings(things: [Thing]) {}
However, definitions within those can leave access control implicit, where appropriate:
internal struct TheFez {
var owner: Person = Joshaber()
}
Rationale: It's rarely appropriate for top-level definitions to be specifically internal
, and being explicit ensures that careful thought goes into that decision. Within a definition, reusing the same access control specifier is just duplicative, and the default is usually reasonable.
Preferred:
extension Optional {
private var isEmpty: Bool {
return self == nil
}
}
Not Preferred:
private extension Optional {
var isEmpty: Bool {
return self == nil
}
}
Use US English spelling to match Apple's API.
Preferred:
let color = "red"
Not Preferred:
let colour = "red"