Swift 2.0 の initializer 自分用まとめ
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html を適当におぼえるためにまとめただけ。
基礎
- すべての property はインスタンス化に初期化されていないといけない
例
// 初期値は declaration と initializer の中どちらでやってもOK struct Fahrenheit { var temperature = 32.0 } struct Fahrenheit { var temperature: Double init() { temperature = 32.0 } }
// initializer はパラメータをとれる struct Celsius { var temperatureInCelsius: Double init(fromFahrenheit fahrenheit: Double) { temperatureInCelsius = (fahrenheit - 32.0) / 1.8 } init(fromKelvin kelvin: Double) { temperatureInCelsius = kelvin - 273.15 } } let boilingPointOfWater = Celsius(fromFahrenheit: 212.0) // boilingPointOfWater.temperatureInCelsius is 100.0 let freezingPointOfWater = Celsius(fromKelvin: 273.15) // freezingPointOfWater.temperatureInCelsius is 0.0
// 初期化のパラメータは local name (initializer body で参照) と external name (呼び出し時に使う) がある // fromFahrenheit が external name, fahrenheit が local name init(fromFahrenheit fahrenheit: Double) {
// external name が指定されなかったら自動で付加される struct Color { let red, green, blue: Double init(red: Double, green: Double, blue: Double) { self.red = red self.green = green self.blue = blue } init(white: Double) { red = white green = white blue = white } }
// external name を使わずにインスタンス化できるようにしたいなら _ を使う struct Celsius { var temperatureInCelsius: Double init(fromFahrenheit fahrenheit: Double) { temperatureInCelsius = (fahrenheit - 32.0) / 1.8 } init(fromKelvin kelvin: Double) { temperatureInCelsius = kelvin - 273.15 } init(_ celsius: Double) { temperatureInCelsius = celsius } } let bodyTemperature = Celsius(37.0) // bodyTemperature.temperatureInCelsius is 37.0
// property がそもそも値を持たないことが想定される場合 // 初期化時に値が決まっていない場合 // などには Optional Property を使う class SurveyQuestion { var text: String var response: String? // こいつが Optional init(text: String) { self.text = text } func ask() { print(text) } } let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?") cheeseQuestion.ask() // prints "Do you like cheese?" cheeseQuestion.response = "Yes, I do like cheese."
// 定数プロパティの初期値は initializer のなかで設定できる class SurveyQuestion { let text: String // ここ var response: String? init(text: String) { self.text = text // これ } func ask() { print(text) } } let beetsQuestion = SurveyQuestion(text: "How about beets?") beetsQuestion.ask() // prints "How about beets?" beetsQuestion.response = "I also like beets. (But not with cheese.)"
// すべての property にデフォルト値が設定されている場合は // 自動で initializer が生成される class ShoppingListItem { var name: String? var quantity = 1 var purchased = false } var item = ShoppingListItem()
// コードの重複を避けるため initalizer が他の initializer を呼ぶことができる struct Rect { var origin = Point() var size = Size() init() {} init(origin: Point, size: Size) { self.origin = origin self.size = size } init(center: Point, size: Size) { let originX = center.x - (size.width / 2) let originY = center.y - (size.height / 2) self.init(origin: Point(x: originX, y: originY), size: size) // これ } }
// designated initializer はクラスの初期化に使われるメインの initializer 。すべての property を初期化したり適切な super クラスの initializer を呼ぶ // クラスはあまり多くの designated initializer を持たない。1つの場合が多い。 // クラスは必ず1つの designated initializer を持たなければならない。継承で得る場合も多い。 // designated initializer の例 init(parameters) { statements }
// Convenience initializers は必須ではない // 特定の使用目的のための initializer を提供するのに便利。その中から designated initializer を呼べば良い convenience init(parameters) { statements }
designated / convenience initializers のルール
- Rule 1: designated initializer は1つ上の super class の designated initializer を呼ばないといけない
- Rule 2: convenience initializer は同じクラスの initializer を呼ばないといけない
- Rule 3: convenience initializer は最終的には designated initializer を呼ばないといけない
initializer の継承
- default では super class からの initializer の継承は*行われない*
- 上記によって child クラスがせっかく特殊用途のクラスなのに、super class の initializer が呼ばれる可能性があって台無し
- 上記の理由により意図的に super class の designated initializer をつかうなら override キーワードを付けないけない
initializer が継承されるルール
- Rule 1: サブクラスが1つも designated initializer がないばあい。自動的にすべての designated initializer を継承する
- Rule 2: Rule 1 か、もしくは明示的に super class のすべての designated initializer を override している場合。自動的に convenience initializer も継承される
Failable Initializers
- initializer が失敗する可能性があるクラスを定義できる
- ? をつけることで initializer が option を返すことを明示できる
struct Animal { let species: String init?(species: String) { if species.isEmpty { return nil } self.species = species } }
Required Initializers
required がついていたら sub class で実装しないチケ内
class SomeClass { required init() { // initializer implementation goes here } }