Swiftのインスタンス生成と解放

Swiftのインスタンス生成と解放を理解するためにサンプルコードを書いてみました。

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

# 1. ２つのインスタンスの生成

```swift
class Car {
    var fuel : Int = 0      // 搭載燃料（残り燃料）量
    
    // 給油関数 (引数：給油量)
    func refuel(fuel : Int) -> Int {
        self.fuel = self.fuel + fuel
        return fuel
    }
}

// fooCar と barCar の２つの自動車インスタンスを生成
var fooCar = Car()
var barCar = Car()

// 初期化直後の残り燃料を表示
print(fooCar.fuel)          // => 0
print(barCar.fuel)          // => 0

// fooCar と barCar に給油する
fooCar.refuel(fuel : 30)    // 30リットル給油
barCar.refuel(fuel : 50)    // 50リットル給油

// 給油後の残り燃料を表示
print(fooCar.fuel)          // => 30
print(barCar.fuel)          // => 50
```

**【 ポイント 】**

1. ２つのインスタンス（車）が存在しているから残り燃料(fuel)は車ごとに異なる。

----

# 2. ２つの変数が１つのインスタンスを参照

```swift
class Car {
    var fuel : Int = 0
    func refuel(fuel : Int) -> Int {
        self.fuel = self.fuel + fuel
        return fuel
    }
}

var fooCar = Car()
var barCar = fooCar         // fooCarを代入する

print(fooCar.fuel)          // => 0
print(barCar.fuel)          // => 0

fooCar.refuel(fuel : 30)
barCar.refuel(fuel : 50)

print(fooCar.fuel)          // => 80
print(barCar.fuel)          // => 80
```

**【 ポイント 】**

1. **fooCar**と**barCar**は一つの同じインスタンスを参照している。だから**fooCar**と**barCar**は常に同じ残り燃料となる。

----

# 3. インスタンスの生成と解放のタイミング

```swift
class Car {
    var fuel : Int = 0
    var color : String
    init(color : String) {
        self.color = color
        print("create \(self.color) car")
    }
    deinit {
        print("destruct \(self.color) car")
    }
    
    func refuel(fuel : Int) -> Int {
        self.fuel = self.fuel + fuel
        return fuel
    }
}

do {
    var fooCar = Car(color: "Red")      // => "create Red car"
    var barCar = Car(color: "Blue")     // => "create Blue car"

    print(fooCar.fuel)
    print(barCar.fuel)

    fooCar.refuel(fuel : 30)
    barCar.refuel(fuel : 50)

    print(fooCar.fuel)
    print(barCar.fuel)
}
                                        // => "destruct Blue car"
                                        // => "destruct Red car"
```

**【 ポイント 】**

1. init() が２回呼ばれている。 => ２つのインスタンスが生成されている。
2. deinit が２回呼ばれている。 => doブロックから出たタイミングで２つのインスタンスが解放されている。

----

# 4. 生存期間(Life-time)が異なる２つのインスタンス

```swift
class Car {
    var fuel : Int = 0
    var color : String
    init(color : String) {
        self.color = color
        print("create \(self.color) car")
    }
    deinit {
        print("destruct \(self.color) car")
    }
    
    func refuel(fuel : Int) -> Int {
        self.fuel = self.fuel + fuel
        return fuel
    }
}

do {
    var fooCar = Car(color: "Red")          // => "create Red car"
    
    do {
        var barCar = Car(color: "Blue")     // => "create Blue car"
        
        print(fooCar.fuel)                  // => 0
        print(barCar.fuel)                  // => 0
        
        fooCar.refuel(fuel : 30)
        barCar.refuel(fuel : 50)
        
        print(barCar.fuel)                  // => 50
    }                                       // => "destruct Blue car"

    print(fooCar.fuel)
}                                           // => "destruct Red car"
```

&nbsp;

**【 ポイント 】**

1. **barCar**が参照しているインスタンスは内側のdoブロックを出るタイミングで解放されている

2. **fooCar**が参照しているインスタンスは外側のdoブロックを出るタイミングで解放されている

----

# 5. ２つの変数が１つのインスタンスを参照　その２

```swift
class Car {
    var fuel : Int = 0
    var color : String
    init(color : String) {
        self.color = color
        print("create \(self.color) car")
    }
    deinit {
        print("destruct \(self.color) car")
    }
    
    func refuel(fuel : Int) -> Int {
        self.fuel = self.fuel + fuel
        return fuel
    }
}

do {
    var fooCar = Car(color: "Red")  // => "create Red car"
    var barCar = fooCar

    print(fooCar.fuel)
    print(barCar.fuel)

    fooCar.refuel(fuel : 30)
    barCar.refuel(fuel : 50)

    print(fooCar.fuel)
    print(barCar.fuel)
}                                   // => "destruct Red car"
```

**【 ポイント 】**

1. インスタンスは１つ（１回）しか生成されていない。
2. その１つのインスタンスを**fooCar**と**barCar**の２つの変数から参照している

----

# 6. 関数引数が参照型のときの関数の外側と内側の変数のふるまい

```swift
class Car {
    var color : String
    init(color : String) {
        self.color = color
        print("create \(self.color) car")
    }
    deinit {
        print("destruct \(self.color) car")
    }
}

func paint(car: Car, color: String) {
    car.color = color
}

do {
    var fooCar = Car(color: "Red")      // => "create Red car"
    var barCar = fooCar
    
    print(fooCar.color)                 // => "Red"
    print(barCar.color)                 // => "Red"
    print(fooCar === barCar ? "同一である" : "同一でない")
                                        // => "同一である"
    
    paint(car: fooCar, color: "Yellow")

    print(fooCar.color)                 // => "Yellow"
    print(barCar.color)                 // => "Yellow"
}                                       // => "destruct Yellow car"
```

**【 ポイント 】**

1. 関数 paint() の外側の**fooCar**も**barCar**も、そして関数 paint() の内側の**car**も、たった一つのインスタンスを参照している。
2. だから、どれか一つの参照型変数のプロパティを書き換えると、他の２つの変数のプロパティも書き換わっている。

----

# 7. 構造体への書き換え

```swift
struct Car {                            // 構造体(struct)で定義
    var color : String
    init(color : String) {
        self.color = color
        print("create \(self.color) car")
    }
    // 構造体はdeinitを記述できない（記述する必要はない）
}

func paint(car: inout Car, color: String) { // 参照渡し(inout)
    car.color = color
}

do {
    var fooCar = Car(color: "Red")      // => "create Red car"
    var barCar = fooCar
    
    print(fooCar.color)                 // => "Red"
    print(barCar.color)                 // => "Red"
    
    paint(car: &fooCar, color: "Yellow")

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

**【 ポイント 】**

1. 構造体(struct)は値型だから**fooCar**と**barCar**は異なる。
2. 関数 paint() の内側でのcarの変更を関数の外側に引き継ぎたい、という理由で参照渡し(inout)を使っている。

----

# 8. NSCopyingプロトコルを継承したインスタンスの複製

```swift
import Foundation

class Car : NSObject, NSCopying {
    var fuel : Int = 0
    var color : String
    
    init(color : String) {
        self.color = color
        print("create \(self.color) car")
    }
    
    deinit {
        print("destruct \(self.color) car")
    }
    
    func copy(with zone: NSZone? = nil) -> Any {
        let copy = Car(color:color)
        copy.fuel = fuel
        return copy
    }
    
    func refuel(fuel : Int) -> Int {
        self.fuel = self.fuel + fuel
        return fuel
    }
}

do {
    var fooCar = Car(color: "Red")
    fooCar.refuel(fuel : 30)                // => "create Red car"
    print(fooCar.fuel)                      // => 30
    
    do {
        var barCar = fooCar.copy() as! Car  // => "create Red car"
        print(barCar.fuel)                  // => 30
        print(fooCar === barCar ? "同一である" : "同一でない")
                                            // => "同一でない"
        
        barCar.refuel(fuel : 50)
        print(barCar.fuel)                  // => 80
    }                                       // => "destruct Red car"

    print(fooCar.fuel)                      // => 30
}                                           // => "destruct Red car"
```

----

# 9. Carをクラス(参照型)から構造体(値型)に書き換え

```swift
struct Car {
    var fuel : Int = 0
    var color : String
    
    init(color : String) {
        self.color = color
        print("create \(self.color) car")
    }
    
    mutating func refuel(fuel : Int) -> Int {
        self.fuel = self.fuel + fuel
        return fuel
    }
}

do {
    var fooCar = Car(color: "Red")
    fooCar.refuel(fuel : 30)            // => 30
    print(fooCar.fuel)
    
    do {
        var barCar = fooCar
        print(barCar.fuel)              // => 30
        barCar.refuel(fuel : 50)
        print(barCar.fuel)              // => 80
    }

    print(fooCar.fuel)                  // => 30
}
```