Swift 3.0 において値型(value type)と参照型(reference type)、値渡しと参照渡し(inout)の振る舞いの違いを理解するためにサンプルコードを書いてみました。

Xcode 8.2.1のPlaygroundで動作を確認しています。

  値渡し 参照渡し
値型 1 2
参照型 3 4

1. 値型(配列)の値渡し

func plusOne(array : [Int]) -> [Int] {
    var array = array
    for i in 0  ..< array.count  {
        array[i] = array[i] + 1
    }
    return array
}

var oldArray = [0, 1, 2]
print(oldArray)                             // => [0, 1, 2]
var newArray = plusOne(array: oldArray)     // => [1, 2, 3]
print(oldArray)                             // => [0, 1, 2]

【 ポイント 】

  1. 配列oldArrayは関数 plusOne() を呼び出す前後で変化しない
  2. Swift 3.0では関数引数は定数(let)。関数引数を直接書き換えることはできない。
  3. Swiftでは配列は「値型 (type value)」である
  4. Objective-Cでは配列(NSArray,NSMutableArray)は参照型である

2. 値型(配列)の参照渡し(inout)

func plusOne(array : inout [Int]) -> [Int] {
    for i in 0  ..< array.count  {
        array[i] = array[i] + 1
    }
    return array
}

var oldArray = [0, 1, 2]
print(oldArray)                             // => [0, 1, 2]
var newArray = plusOne(array: &oldArray)    // => [1, 2, 3]
print(oldArray)                             // => [1, 2, 3]

【 ポイント 】

  1. 参照渡し inout
  2. 配列oldArrayは関数 plusOne() を呼び出す前後で変化する

3. 参照型(クラスのインスタンス)の値渡し

class Car {
    var color : String

    init(color : String) {
        self.color = color
    }
}

func swap(car1: Car, car2: Car) {
    let tmp = car1.color
    car1.color = car2.color
    car2.color = tmp
}

do {
    var fooCar = Car(color: "Red")
    var barCar = Car(color: "Blue")

    print(fooCar.color)     // => "Red"
    print(barCar.color)     // => "Blue"

    swap(car1: fooCar, car2: barCar)

    print(fooCar.color)     // => "Blue"
    print(barCar.color)     // => "Red"
}

【 ポイント 】

  1. 関数外のfooCarと関数内のcar1は同じインスタンスを参照している
  2. 関数外のbarCarと関数内のcar2は同じインスタンスを参照している
  3. その結果、関数内でcar1car2のプロパティ(color)を書き換えると関数外の変数fooCarbarCarのプロパティも書き換わる

4. 参照型(クラスのインスタンス)の参照渡し

class Car {
    var color : String

    init(color : String) {
        self.color = color
    }
}

func swap(car1: inout Car, car2: inout Car) {
    let tmpCar : Car

    tmpCar = car1
    car1 = car2
    car2 = tmpCar
}

do {
    var fooCar = Car(color: "Red")
    var barCar = Car(color: "Blue")

    print(fooCar.color)
    print(barCar.color)

    swap(car1: &fooCar, car2: &barCar)

    print(fooCar.color)
    print(barCar.color)
}

【 ポイント 】

  1. 参照渡しされた引数を直接書き換えている
  2. インスタンスの内容を書き変えたのではなく、引数(変数)が参照している先(インスタンス)を差し替えている。