イニシャライザ
ここで、は Swift のクラス及び構造体で、オブジェクトを初期化する方法について説明します。
他の多くのオブジェクト指向言語での初期化の仕組みは、コンストラクタという名前で出てきますが、Swift のイニシャライザはちょっと違います。
Swift では初期化を行なうためのルールがいくつかあり、確実にオブジェクトを初期化するようになっています。
必ずストアドプロパティの初期化を
クラスでも構造体でも、ストアドプロパティは必ず初期化しないといけないことになっています。
初期化を行なうメソッドは init という名前で、これをイニシャライザ (initializer) といいます。
原則的にイニシャライザは必要です。
ただし、全てのストアドプロパティのデフォルト値がある場合は、init を全く書かなくともデフォルトイニシャライザ (default initializer) が暗黙的に作成されます。
構造体の場合は、全てのストアドプロパティにデフォルト値がなかったとしても、メンバーワイズ・イニシャライザ (memberwise initializer) が暗黙的に作成されます。
イニシャライザ・デリゲーション
イニシャライザは複数定義することが可能です。
イニシャライザ内からイニシャライザを呼ぶことを、イニシャライザ・デリゲーション (initializer delegation) といいます。
デリゲーションは「委任」の意味ですね。「任せる」ということです。あるイニシャライザから他のイニシャライザに初期化を任せるということです。
イニシャライザのデリゲーション・ルール
さらにもう少し詳しくデリゲーションをみていきます。そのために必要な概念を定義します。
デジグネイテッド・イニシャライザ
上記の一番目のイニシャライザのように、全てのプロパティを初期化するイニシャライザのことを、デジグネイテッド・イニシャライザ (designated initializer) といいます。 デジグネイテッド・イニシャライザがプライマリ・イニシャライザとなります。
designated は「指定」「指名」の意味です。プロ野球の指名打者 (DH) の D は、この designated の D ですね。
Swift のクラス定義では最低ひとつのデジグネイテッド・イニシャライザが必要です。
コンビニエンス・イニシャライザ
一方、デジグネイテッド・イニシャライザ以外の、副次的なイニシャライザはコンビニエンス・イニシャライザ (convenience initializer) といいます。
イニシャライザの呼び出しルール
イニシャライザは以下のルールで呼び合うことで、初期化を確実にわかりやすく実行します。
- デジグネイテッド・イニシャライザはひとつ上のスーパークラスのデジグネイテッド・イニシャライザを呼ばなければならない。(もしあれば)
- コンビニエンス・イニシャライザは同じクラスの他のイニシャライザを呼ばなければならない。
- コンビニエンス・イニシャライザからのイニシャライザの呼び出しチェーンは、最終的にデジグネイテッド・イニシャライザを呼ばねばならない。
図にすると、次のようになります。
失敗可能なイニシャライザ
オブジェクトの初期化を失敗させることも可能です。これを失敗可能なイニシャライザ (フェイラブル・イニシャライザ) といいます。
この場合 init? として、パラメータの条件によって nil を返します。
class Person {
var age : Int
var name : String
init? ( name : String, age : Int ){
if( name.isEmpty || age < 0 ){
self.age = 0
self.name = ""
return nil
}
self.age = age
self.name = name
}
}
var p1 = Person( name : "Ichiro" , age : 30 )
if let p2 = Person( name : "Hanako" , age : -1 ) {
print( "p2 OK" )
print( "p2.name = \(p2.name)" )
}
else {
print( "p2 nil" )
}
会社クラスの具体例
具体例をみてみましょう。
次の「会社 Company 」クラスでは、ストアドプロパティが二つあります。ひとつは会社名を保持する name。もうひとつは会社の id を保持する Int 型の id です。
イニシャライザは二つ定義してあります。
class Company {
var name : String
var id : Int
init( name : String , id : Int ){
self.name = name
self.id = id
}
convenience init( id : Int ){
var name : String
switch( id ){
case 1:
name = "ABC Company"
default:
name = "(Unknown)"
}
self.init( name : name, id : id )
}
}
var c = Company( id : 1 )
print( c.name )
最初の init では二つのストアドプロパティ両方に対する初期化値を受け取って、それぞれ値をセットしています。
二番目の init では id だけを受け取って、id が 1 の場合は会社名を "ABC Company" として、それ以外の場合は "Unknown" (不明) としています。
二番目の init からは self.init として、一番目の init を呼び出しています。繰り返しになりますが、このように init から init を呼ぶのが、イニシャライザデリゲーションです。