Home

Awesome

Swift Cheat Sheet

Notes taken from The Swift Programming Language.

Topics

The Basics

Constants & Variables

Comments

// this is a comment
/* multiple lines comment */
/* /* nested multilines supported */ */

Semicolons

// No semicolon, unless for multiple statements on a single line
let cat="hello"; println(cat)

Integers

Floating Point Numbers

Type Safety and Type Inference

Numeric Literals

Numeric Type Conversion

Type Aliases

Booleans

Tuples

Optionals

Assertions

Basic Operators

Overview

Terminology

// Unary
prefix: !b
postfix: i++

// Binary
2 + 3

// Ternary
a ? b : c

Assignment Operator

let b = 10
let (x,y) = (1,2)
if x = y { // invalid }

Arithmetic Operators

Compound Assignment Operators

Comparison Operators

Ternary Conditional Operator

Nil Coalescing Operator

Range Operators

Logical Operators

Strings and Characters

Overview

"hello world"

String Literals

let someString = "Some string literal value"

Initializing an Empty String

var emptyString = ""
var anotherEmptyString = String()

emptyString == anotherEmptyString

if emptyString.isEmpty { ... }

String Mutability

let constantString = "hello"
constantString += " world"   // compilation error

String Are Value Types

Working with Characters

Concatenating Strings & Characters

var welcome = "string1" + "string2"
welcome.append("!")

String Interpolation

let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"

Unicode

Counting Characters

let unusualMenagerie = "Koala , Snail , Penguin , Dromedary"
println("unusualMenagerie has \(countElements(unusualMenagerie)) character
// prints "unusualMenagerie has 40 characters

Comparing Strings

Unicode Representations of Strings

Collection Types

Overview

Mutability of Collections

Arrays

Dictionaries

Control Flow

For Loops

While Loops

Conditional Statements

Control Transfer Statements

Functions

Defining and Calling Functions

func sayHello(personName: String) -> String {
  let greeting = "Hello, " + personName + "!"
  return greeting
}

sayHello("Anna")

Function Parameters & Return Values

Function Parameter Names

fund someFunction(paramName: Int) { ... }
* Param only be used inside the function

Function Types

// Function Type as a parameter type for another function
func printMathResult(mathFunc: (Int, Int) -> Int, a: Int, b:Int) { ... }
printMathResult(addTwoInts, 3, 5)

// Function Type as Return Types
func someFunc(backwards: Bool) -> (Int) -> Int {
  return backwards ? stepBackward : stepForward
}

Nested Functions

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
  func stepForward(input: Int) -> Int { return input + 1 }
  func stepBackward(input: Int) -> Int { return input - 1 }
  return backwards ? stepBackward : stepForward
}

Closures

Overview

Closure Expressions

Trailing Closures

Capturing Values

Closures are Reference Types

Enumerations

Overview

Enumeration Syntax

enum SomeEnumeration {
  // enumeration definition goes here
}

enum CompassPoint {
  case North
  case South
  case East
  case West
}

Matching Enumeration Values with a Switch Statement

directionToHead = .South
  switch directionToHead {
    case .North:
      println("Lots of planets have a north")
    case .South:
      println("Watch out for penguins")
    case .East:
      println("Where the sun rises")
    case .West:
      println("Where the skies are blue")
  }

Associated Values

Raw Values

Classes & Structures

Overview

Comparing Classes and Structures

Structures and Enumerations are Value Types

Classes Are Reference Types

Choosing Between Classes and Structures

Assignment and Copy Behavior for Strings, Arrays, and Dictionaries

Properties

Overview

Stored Properties

Computed Properties

Property Observers

Global and Local Variables

Type Properties

Methods

Overview

Instance Methods

class Counter {
    var count = 0
    func increment() {
        count++
    }
    func incrementBy(amount: Int) {
        count += amount
    }
    func reset() {
        count = 0
    }
}

Type Methods

Subscripts

Overview

Subscript Syntax

Subscript Usage

Subscript Options

Inheritance

Overview

Defining a base class

Subclassing

Overriding

Preventing Overrides

Initialization

Overview

Setting Initial Values for Stored Properties

Customizing Initialization

Default Initializers

Initializer Delegation for Value Types

size: Size(width: 5.0, height: 5.0)) // originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0) ```

Class Inheritance and Initialization

Setting a Default Property Value with a Closure or Function

class SomeClass {
    let someProperty: SomeType = {
        // create a default value for someProperty inside this closure
        // someValue must be of the same type as SomeType
        return someValue
        }()
}

Deinitialization

Overview

How Deinitialization works

Deinitializers in Action

struct Bank {
    static var coinsInBank = 10_000

    static func vendCoins(var numberOfCoinsToVend: Int) -> Int {
        numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank)
        coinsInBank -= numberOfCoinsToVend
        return numberOfCoinsToVend

    }

    static func receiveCoins(coins: Int) {
        coinsInBank += coins
    }

}

class Player {
    var coinsInPurse: Int

    init(coins: Int) {
        coinsInPurse = Bank.vendCoins(coins)
    }

    func winCoins(coins: Int) {
        coinsInPurse += Bank.vendCoins(coins)
    }

    deinit {
        Bank.receiveCoins(coinsInPurse)
    }
}

var playerOne: Player? = Player(coins: 100)

println("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
// prints "A new player has joined the game with 100 coins"

println("There are now \(Bank.coinsInBank) coins left in the bank")
// prints "There are now 9900 coins left in the bank

playerOne!.winCoins(2_000)

println("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
// prints "PlayerOne won 2000 coins & now has 2100 coins"

println("The bank now only has \(Bank.coinsInBank) coins left")
// prints "The bank now only has 7900 coins left

playerOne = nil

println("PlayerOne has left the game")
// prints "PlayerOne has left the game"

println("The bank now has \(Bank.coinsInBank) coins")
// prints "The bank now has 10000 coins

Automatic Reference Counting

Overview

How ARC Works

ARC In Action

class Person {
    let name: String
    init(name: String) {
        [self.name][2] = name
        println("\(name) is being initialized")
    }
    deinit {
        println("\(name) is being deinitialized")
    }
}
var reference1: Person?
var reference2: Person?
var reference3: Person?

reference1 = Person(name: "John Appleseed")
// prints "John Appleseed is being initialised"

reference2 = reference1
reference3 = reference1
reference1 = nil
reference2 = nil
reference3 = nil
// prints "John Appleseed is being deinitialized

Strong Reference Cycles Between Class Instances

Resolving Strong Reference Cycles Between Class Instances

Strong Reference Cycles for Closures

Resolving Strong Reference Cycles for Closures

Optional Chaining

Overview

Optional Chaining as an Alternative to Forced Unwrapping

Defining Model Classes for Optional Chaining

Accessing Properties Through Optional Chaining

Calling Methods Through Optional Chaining

Accessing SubscriptsThrough Optional Chaining

Linking Multiple Levels of Chaining

Chaining on Methods with Optional Return Values

Type Casting

Overview

Defining a Class Hierarchy for Type Casting

class MediaItem {
    var name: String
    init(name: String) {
        [self.name][2] = name
    }
}
class Movie: MediaItem {
    var director: String
    init(name: String, director: String) {
        self.director = director
        super.init(name: name)
    }
}

class Song: MediaItem {
    var artist: String
    init(name: String, artist: String) {
        self.artist = artist
        super.init(name: name)
    }
}
let library = [
    Movie(name: "Casablanca", director: "Michael Curtiz"),
    Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
    Movie(name: "Citizen Kane", director: "Orson Welles"),
    Song(name: "The One And Only", artist: "Chesney Hawkes"),
    Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]

Checking Type

Downcasting

Type Casting for Any and AnyObject

Nested Types

Overview

Nested Types in Action

struct BlackjackCard {
    // nested Suit enumeration
    enum Suit: Character {
        case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣"
    }

    // nested Rank enumeration
    enum Rank: Int {
        case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten
        case Jack, Queen, King, Ace

        struct Values {
            let first: Int, second: Int?
        }

        var values: Values {
            switch self {
              case .Ace:
                  return Values(first: 1, second: 11)
              case .Jack, .Queen, .King:
                  return Values(first: 10, second: nil)
              default:
                  return Values(first: self.toRaw(), second: nil)
            }
        }
    }

    // BlackjackCard properties and methods
    let rank: Rank, suit: Suit
    var description: String {
        var output = "suit is \(suit.toRaw()),"
        output += " value is \(rank.values.first)"

        if let second = rank.values.second {
            output += " or \(second)"
        }

        return output
    }
}

let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
println("theAceOfSpades: \(theAceOfSpades.description)")
// prints "theAceOfSpades: suit is ♠, value is 1 or 11

Referring to Nested Types

  let heartsSymbol = BlackjackCard.Suit.Hearts.toRaw()
  // heartsSymbol is "♡"

Extensions

Overview

Extension Syntax

extension SomeType {
  // new functionality to add to SomeType goes here
}

// Extend with protocols
extension SomeType: SomeProtocol, AnotherProtocol {
  // implementation of protocol requirements goes here
}

Computed Properties

Initializers

Methods

Subscripts

extension Int {
    subscript(var digitIndex: Int) -> Int {
        var decimalBase = 1
        while digitIndex > 0 {
            decimalBase *= 10
            --digitIndex
        }
        return (self / decimalBase) % 10
    }
}
746381295[0]  // returns 5
746381295[1]  // returns 9
746381295[2]  // returns 2
746381295[8]  // returns 7
746381295[9]  // returns 0, as if you had requested:
0746381295[9]

Nested Types

extension Int {
    enum Kind {
        case Negative, Zero, Positive
    }

    var kind: Kind {
        switch self {
        case 0:
            return .Zero
        case let x where x > 0:
            return .Positive
        default:
            return .Negative
        }
    }
}

func printIntegerKinds(numbers: [Int]) {
    for number in numbers {
        switch number.kind {
        case .Negative:
            print("- ")
        case .Zero:
            print("0 ")
        case .Positive:
            print("+ ")
        }
    }
    print("\n")
}

printIntegerKinds([3, 19, -27, 0, -6, 0, 7])  // prints "+ + - 0 - 0 +"

Protocols

Overiew

Protocol Syntax

protocol SomeProtocol {
  // protocol definition goes here
}

struct SomeStructure: FirstProtocol, AnotherProtocol {
  // structure definition goes here
}
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
  // class definition goes here
}

Protocol Requirements

Method Requirements

Mutating Method Requirements

Initializer Requirements

Protocols as Types

Delegation

protocol DiceGame {
    var dice: Dice { get }
    func play()
}

protocol DiceGameDelegate {
    func gameDidStart(game: DiceGame)
    func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
    func gameDidEnd(game: DiceGame)
}

class SnakesAndLadders: DiceGame {
    let finalSquare = 25
    let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
    var square = 0
    var board: [Int]
    init() {
        board = [Int](count: finalSquare + 1, repeatedValue: 0)
        board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
        board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
    }
    var delegate: DiceGameDelegate?
    func play() {
        square = 0
        delegate?.gameDidStart(self)
        gameLoop: while square != finalSquare {
            let diceRoll = dice.roll()
            delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
            switch square + diceRoll {
            case finalSquare:
                break gameLoop
            case let newSquare where newSquare > finalSquare:
                continue gameLoop
            default:
                square += diceRoll
                square += board[square]
            }
        }
        delegate?.gameDidEnd(self)
    }
}

class DiceGameTracker: DiceGameDelegate {
    var numberOfTurns = 0
    func gameDidStart(game: DiceGame) {
        numberOfTurns = 0
        if game is SnakesAndLadders {
            println("Started a new game of Snakes and Ladders")
        }
        println("The game is using a \(game.dice.sides)-sided dice")
    }
    func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
        ++numberOfTurns
        println("Rolled a \(diceRoll)")
    }
    func gameDidEnd(game: DiceGame) {
        println("The game lasted for \(numberOfTurns) turns")
    }
}

let tracker = DiceGameTracker()
let game = SnakesAndLadders()
game.delegate = tracker
game.play()

Adding Protocol Conformance with an Extension

Collections of Protocol Types

Protocol Inheritance

Class-Only Protocol

Protocol Composition

Checking for Protocol Conformance

Optional Protocol Requirements

Generics

Overview

The Problem That Generic Solve

Generic Functions

func swapTwoValues<T>(inout a: T, inout b: T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

Type Parameters

Generic Types

Extending a Generic Type

Type Constraints

Associated Types

Where Clause

Access Control

Overview

Modules and Source Files

Access Levels

Access Control Syntax

Constants, Variables, Properties, and Subscripts

Initializers

Protocols

Extensions

Generics

TypeAliases

References