Swiftに関するメモ その5 - 初期化処理・終了処理


* [
Swiftに関するメモ - 一覧](http://qiita.com/takkyun/items/f34abf857deed808c610)

https://developer.apple.com/swift/ より

[The Swift Programming Language (iBooks Store)](https://itunes.apple.com/us/book/the-swift-programming-language/id881256329?mt=11)をざっくり目を通してつらつらと。

# 初期化処理
## イニシャライザ (Initializer)

[Swiftに関するメモ その4 - 継承](http://qiita.com/takkyun/items/ddacd2cd8fb5c56a66d9)でも触れましたが、`init` というメソッドを定義することによって、クラスや構造体のインスタンスが生成される (初期化される) 際に呼ばれる処理を実装することができます。

```swift
class SomeClass {
  var someValue: Int
  init() {
    someValue = 2
  }
}

let aClass = SomeClass() // aClass.someValue は 2
```

## プロパティの初期値

プロパティの宣言時に初期値を設定することで、`init` メソッドを使わなくても初期値を決めることができます。

```swift
class SomeClass {
  var someValue: Int = 2
}

let aClass = SomeClass() // aClass.someValue は 2
```

`init` メソッドでのプロパティの値を設定すると、プロパティの初期値を上書きするような動作になります。

したがって、

```swift
class SomeClass {
  init() {
    someValue = 1
  }
  var someValue: Int = 2
}

let aClass = SomeClass() // aClass.someValue は 1
```

のようになります。ただ、このサンプルは悪い書き方の例です。

コードの読みやすさの面でもプロパティの宣言は `init` より前に記述した方が無難だと思います。

## クロージャを使ったプロパティの初期値

プロパティの初期値には定数だけでなく、関数を指定することもできます。

```swift
class Fibonacci10 {
  let values: Int[] = {
    var array = [0, 1];
    for n in 2...9 {
      array += array[n - 2] + array[n - 1]
    }
    return array;
  }()
}

let fibonacci = Fibonacci10() // fibonacci.values = [0,1,1,2,3,5,8,13,21,34]
```

この例の場合、`values` に指定されたクロージャが実行され、その戻り値が初期値として代入されます。

## `init` メソッドの引数

`init` メソッドは引数を取ることができます。

```swift
class SomeClass {
  var someValue: Int = 2
  init(value:Int) {
    someValue = value
  }
}

let aClass = SomeClass(value:3) // aClass.someValue は 3
```

`value` というインスタンスの初期化に必要なパラメータを設定します。

この時、`init` メソッドのパラメータ `value` は引数の名前として指定する必要があります。

```swift
class SomeClass {
  var someValue: Int = 2
  init(value:Int) {
    someValue = value
  }
}

let aClass = SomeClass(3) // エラー!!!
```

もし引数が自明で名前は必要ないという場合は `_` を利用します。

```swift
class SomeClass {
  var someValue: Int = 2
  init(_ value:Int) {
    someValue = value
  }
}

let aClass = SomeClass(3) //  aClass.someValue は 3
```

## 定数の初期化

定数なプロパティも `init` メソッドでは初期値の置き換えが可能です。

```swift
class SomeClass {
  let someValue: Int = 2
  init(value:Int) {
    someValue = value
  }
}

let aClass = SomeClass(value:3) // aClass.someValue は 3
```

## 構造体の `init` メソッドの省略

構造体では `init` メソッドを省略して、プロパティの名前で引数を渡すことによってプロパティの初期化ができます。

```swift
struct SomeStructure {
  let someValue: Int
}
let aStruct = SomeStructure(someValue:2) // aStruct.someValue は 2
```

というコードは

```swift
struct SomeStructure {
  let someValue: Int
  init(someValue:Int) {
    self.someValue = someValue
  }
}
let aStruct = SomeStructure(someValue:2) // aStruct.someValue は 2
```

と同義です。

## 複数の `init` メソッド

引数の異なる複数の `init` メソッドを定義することができます。

```swift
struct SomeStructure {
  let someValue: Int
  init() {
    someValue = 1
  }
  init(value:Int) {
    someValue = value
  }
}
let aStruct = SomeStructure() // aStruct.someValue は 1
let anotherStruct = SomeStructure(value:2) // anotherStruct.someValue は 2
```

## `convenience` な `init` メソッド

クラスでも複数の `init` メソッドを定義できます。

その際、必ず実行される `init` メソッドと利便性のために補助的に利用される `init` メソッドを定義することができます。

```swift
class SomeClass {
  let someValue:Int
  init(value:Int) {
    someValue = value
  }
  convenience init(stringValue:String) {
    self.init(value:stringValue.toInt()!);
  }
}
```

`convenience` に指定された `init` メソッドからは必ず「指定された (Designated)」`init` メソッドを呼ぶ必要があります。

Designated `init` の概念は継承したクラスにも適用されます。ベースクラスに Designated な `init` メソッドがある場合には、それらが `super.init` で呼ばれる必要があります。

# 終了処理 (`deinit`)

Objective-C でいうところの `dealloc` と同じようにインスタンスが破棄されるタイミングで呼ばれる `deinit` を定義することができます。

`deinit` は引数をとることができず、また継承したクラスでもベースクラスの `deinit` は自動的に呼ばれるため、`super.deinit` のように明示的に呼ぶ必要はありません。