しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

Swift再入門15 − The Swift Programming Languageを読んでみる

この記事では「The Swift Programming Language」を1から読んだ感想とか発見を書いてみようと思います。
「The Swift Programming Language」とはSwiftの公式ドキュメントでiBooksや下ページで見る事ができます。

The Swift Programming Language (Swift 2.1): About Swift

読んだ所

今回はInitializationという項目を読みました。

The Swift Programming Language (Swift 2.1): Initialization

学んだこと

パラメータなしのInitializer

_を最初につければパラメータの指定が不要です。

class SuperClass {
    init(_ value: Double) {
    }
}
SuperClass(1)

デフォルトInitializer

initializerが定義されていない場合はSuperClass()という形で初期化できます。

class SuperClass {
}
SuperClass()

Designated InitializersとConvenience Initializers

Designated Initializersが通常のInitializerでConvenienceは下のように書くInitializerです。

convenience init(value: String) {
    self.init(value: Double(value) ?? 0)
}

2種類のInitializerは下のルールが適用されるようです。

  1. A designated initializer must call a designated initializer from its immediate superclass.
  2. A convenience initializer must call another initializer from the same class.
  3. A convenience initializer must ultimately call a designated initializer.

A designated initializer must call a designated initializer from its immediate superclass.

designated initializerは親クラスのdesignated initializerを呼び出す必要があるようです。
下のサンプルではsuper.init(intValue: 1)を呼ばないとエラーになりました。

class SuperClass {
    init(intValue: Int) {}
}

class SubClass: SuperClass {
    var value: Double?
    
    init(value: Double) {
        super.init(intValue: 1)
        self.value = value
    }
}

親クラスがdesignated initializerを持っていなければ呼ぶ必要がないです。

class SuperClass {
}

class SubClass: SuperClass {
    var value: Double?
    
    init(value: Double) {
        self.value = value
    }
}

A convenience initializer must call another initializer from the same class.

convenience initializerは同じクラスのInitializerを呼ばなければいけません。

class SubClass: SuperClass {
    var value: Double?
    
    init(value: Double) {
        self.value = value
        super.init(value: 1)
    }
    
    convenience init() {
        self.init(value: 1) // self.initを呼ばないとエラー
    }
}

自分以外のInitializerがない時はデフォルトのInitializerを呼ぶ必要があります。

class SubClass: SuperClass {
    var value: Double?
    
    convenience init() {
        self.init()
    }
}

親クラスのInitializerを呼ぼうとするとエラーです。

class SubClass: SuperClass {
    var value: Double?
    
    convenience init() {
        super.init() // これはエラー
    }
}

逆にdesignated initializerは同じクラスのInitializerを呼べません。

A convenience initializer must ultimately call a designated initializer.

convenience initializerは最終的にdesignated initializerを呼ぶ必要があります。

呼び出し先がdesignated initializerを呼んでいるならconvenience initializerからconvenience initializerを呼び出す事もできるという事です。

class SubClass: SuperClass {
    var value: Double?
    
    init(value: Double) {
        self.value = value
        super.init(value: 1)
    }
    
    convenience init(value1: Double) {
        self.init(value: 1)
    }
    
    convenience init(value2: Double) {
        self.init(value1: 1)
    }
}

OptionalなInitializer

下のように条件によってnilを返すInitializerも定義できます。

class SuperClass {
    init?(value: Double) {
        if value == 0 { return nil }
    }
}

init!はImplicitlyUnwrappedOptional型の変数を返します。

class SuperClass {
    init!(value: Double) {
        if value == 0 { return nil }
    }
}

required

requiredを付けられたInitializerはサブクラスでオーバーライドしなければいけません。

class SuperClass {
    var value: Int
    required init(value: Int) {
        self.value = value
    }
}

class SubClass: SuperClass {
    required init(value: Int) {
        super.init(value: value)
    }
    
    init(value1: Int) {
        super.init(value: value1)
    }
}

Initializerが1件もない場合はrequiredなInitializerをオーバーライドする必要はありません。

class SuperClass {
    var value: Int
    required init(value: Int) {
        self.value = value
    }
}

class SubClass: SuperClass {
}

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

Initializerと少し話題がそれますが、プロパティーの初期化は下のようにクロージャーを使えます。

class SuperClass {
    var value: Int = {
        return 1
    }()
}