menu

Swift Style Guidelines

Whitespace

Indentation

Before lines, use 4 spaces, not tabs (set this in your preferences). Allow the IDE to guide your indentation practices; if it automatically indents something, don’t change that, but adopt it.

Always indent inside curly-brace-blocks, with the sole exception of switch cases, which appear at the same indentation level as the switch statement, itself.

When there are multiple parts of an if, else, guard, or while statement, chop them down and align as the IDE prefers. This makes it clear that you have one clear intent for each line.

Good Bad
if (!foo && baz)
    || (qux && baz) {
    // Content...
}

guard
    let hoge = self.hoge,
    let norf = hoge.norf,
    norf.isInitialized
    else {
        assertionFailure("hoge and norf are required")
        return
}
if (!foo && baz) || (qux && baz) {
  // Content...
}

guard let hoge = self.hoge, let norf = hoge.norf, norf.isInitialized else {
	assertionFailure("hoge and norf are required")
	return
}
switch parseError {
case nil:
    return .success

case .undefinedKey:
    continue

case .unexpectedToken:
    return .failure
}
switch parseError {
    case nil:
        return .success

    case .undefinedKey:
        continue

    case .unexpectedToken:
        return .failure
}

Chopping-Down Functions

When a function has a long declaration with many parameters, it may be chopped-down at both the declaration and the call site. That is to say, hard-wrapped so that they align nicely. If you prefer to keep it all on one line, that is also OK.

Don’t chop-down Objective-C style (so that colons align).

Good Bad
func foobar(_ baz: Baz,
            for qux: Qux,
            hoge: Hoge,
            norfProvider: (() -> Norf)?) -> Foobar {
    // Content...
}
func foobar(_ baz: Baz, for qux: Qux, hoge: Hoge, norfProvider: (() -> Norf)?) -> Foobar {
    // Content...
}
let x = foobar(baz,
               for: Qux(),
               hoge: baz.hoge,
               norfProvider: nil)
let x = foobar(baz, for: Qux(), hoge: baz.hoge, norfProvider: nil)
func foobar(_ baz: Baz, for qux: Qux,
    hoge: Hoge, norfProvider: (() -> Norf)?) -> Foobar {
    // Content...
}
func foobar(_ baz: Baz,
          for qux: Qux,
             hoge: Hoge,
     norfProvider: (() -> Norf)?
) -> Foobar {
    // Content...
}
let x = foobar(baz, for: Qux(),
    hoge: baz.hoge, norfProvider: nil)
let x = foobar(baz,
           for: Qux(),
          hoge: baz.hoge,
  norfProvider: nil)

Inline Padding

The quick summary of the below table is:

  • Colons are X: Y or X : Y
  • Put a space before opening curly braces
  • Put a space around the assignment “=
  • Don’t put spaces around parentheses and angle brackets unless some other rule dictates that you should
  • Keep parentheses as close to the tokens they group as possible
Place Number of spaces Good Bad

Around typing colon

  • 0 or 1 before
  • 1 after

Depending on preference

class Foo: Bar {
    // Content...
}

struct Baz : Qux {
    let hoge: Hoge
    var norf : Norf
}
class Foo:Bar {
    // Content...
}

struct Baz :Qux {
    let hoge:Hoge
    var norf :Norf
}

Generics’ angle brackets

  • 0

Keep them flush with the type they modify and the types within them.

Rules dictating more spacing override this (do place a space after closing angle bracket and opening curly brace).

class Foo<Baz> {
    // Content...
}

class Bar: Qux<Hoge, Norf> {
    // Content...
}
class Foo < Baz > {
    // Content...
}

class Bar: Qux <Hoge, Norf> {
    // Content...
}

After type declaration

Between last declaration character and opening curly brace

  • 1
struct Foo {
    // Content...
}

protocol Bar: Baz {
    // Content...
}

class Qux: Hoge<Norf> {
    // Content...
}
struct Foo  {
    // Content...
}

protocol Bar: Baz{
    // Content...
}

class Qux: Hoge<Norf>{
    // Content...
}

Around assignment “=

Around operators

  • 1

Consecutive assignments are allowed to have more spacing for pretty alignment.

Note that Swift will not allow things like x= y or x =y.

let foo    = 5 + 7
var bazqux = false
let hoge   = "norf"
let foo = 5 + 7
var bazqux = false
let hoge = "norf"
let foo=5+7
var foobar  =  false
let hoge =     "norf"
let foo =    5 + 7
var bazqux = false
let hoge =   "norf"

Functions

  • 0 between name and open parenthesis
  • 0 between open parenthesis and first parameter label (or close parenthesis if no parameters)
  • 0 before commas between parameters
  • 1 after commas between parameters
  • 0 between last parameter and close parenthesis
  • 1 between close parenthesis and open brace
func foo(bar baz: Qux, hoge: Norf) {
    // Content...
}

func foo2() -> Bool {
    return true
}
func foo ( bar baz: Qux , hoge: Norf ){
    // Content...
}

func foo2( )->Bool{
    return true
}

if, else, guard, switch, while, and for statements

  • 1 around (but not within) necessary parentheses
  • 1 before opening brace Spaces emerge from other rules;

First write or imagine it without parentheses. Then, place parentheses as necessary to group elements.

guard foo else {
    assertionFailure("need foo")
    return
}

if (bar && baz) || qux {
    // Content...
}
guard ( foo ) else{
    assertionFailure("need foo")
    return
}

if(bar && baz) || qux{
    // Content...
}

Blank Lines

When in doubt, more blank lines are okay. It’s better for readability when things are spaced out rather than crammed together, and storage/bandwidth/compile time is not a concern.

The quick summary of the below table is:

  • 0 or 1 blank line between fields
  • 2 blank lines between functions and other such blocks
  • 3 blank lines between classes and other types
Place Number of spaces Good Bad

Before opening comment

(copyright, file documentation, etc.)

  • 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//
//  MyFile.swift
//  Project Name
//
//  Created by Ben Leggiero on 2019-07-16
//  Copyright © 2019 Ben Leggiero. All rights reserved.
//

import Cocoa
import FancySDK


let defaultFooSize = 5
fileprivate var instanceCount = 0



class Foo {

    private var usageCount = 0
    let size: Int


    var intValue: Int {
        return usageCount + size
    }


    // MARK: Initialization

    init(size: Int) {
        instanceCount += 1
        self.size = size
    }


    convenience init() {
        self.init(size: defaultFooSize)
    }


    // MARK: Class-specific functions

    func bar() {
        print("Bar!")
        usageCount += 1
    }


    func handleWithBaz(text: String) {

        if let baz = FancySDK.baz {

            let hogeText = text.hoge()
            baz.handle(hogeText)
        }

        print("Did handle baz")

        usageCount += 1
    }
}



// MARK: - Extensions

extension String {
    func hoge() -> String {
        return self + " - Hoge"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//
//  MyFile.swift
//  Project Name
//
//  Created by Ben Leggiero on 2019-07-16
//  Copyright © 2019 Ben Leggiero. All rights reserved.
//
import Cocoa
import FancySDK

let defaultFooSize = 5
fileprivate var instanceCount = 0

class Foo {
    private var usageCount = 0
    let size: Int
    var intValue: Int {
        return usageCount + size
    }


    // MARK: Initialization

    init(size: Int) {
        instanceCount += 1
        self.size = size
    }
    convenience init() {
        self.init(size: defaultFooSize)
    }

    // MARK: Class-specific functions
    func bar() {
        print("Bar!")
        usageCount += 1
    }

    func handleWithBaz(text: String) {
        if let baz = FancySDK.baz {
            let hogeText = text.hoge()
            baz.handle(hogeText)
        }
        print("Did handle baz")
        usageCount += 1
    }

}
// MARK: - Extensions
extension String {
    func hoge() -> String {
        return self + " - Hoge"

    }

}

Between opening comment and group of imports

  • 1

After group of imports

  • 2 or 3

Depending on following number of variables/constants outside scope

Around group of variables/constants outside scope

  • 2 or 3

Depending on number of variables/constants outside scope

Around types (classes, enums, etc.)

  • 3

At beginning of type

After opening brace and before actual code

0 or 1

Depending on preference

Around functions and other scoped blocks

  • 2

At beginning of functions and other scoped blocks

After opening brace and before actual code

  • 0 or 1

Depending on preference

At the end of functions and other scoped blocks

  • 0

Around variables

  • 0 or 1

Depending on complexity of declaration

Around local blocks (if, closures, etc.)

  • 1

Before // MARK:

  • 2

Before // MARK: -

  • 3

After // MARK: and // MARK: -

  • 1

Line breaks

Place Number of spaces Good Bad
  • After type declaration attribute
  • After function attribute
  • After member attribute
  • 1
@objc
class Foo: NSObject {
    @objc
    @IBAction
    func bar(_ sender: Any?) {
        // Content...
    }


    @objc(baz)
    var qux: Hoge? = nil


    func norf(callback: @escaping () -> Void) {
        // Content...
    }
}
@objc class Foo: NSObject {
    @objc @IBAction
    func bar(_ sender: Any?) {
        // Content...
    }


    @objc(baz)


    var qux: Hoge? = nil


    func norf(callback: @escaping
                        () -> Void) {
        // Content...
    }
}