Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

  1. トップページ
  2. Swift入門編 - イニシャライザ(コンストラクタ)について

イニシャライザ(コンストラクタ)について

みなさまどうも。

続きまして前回やったクラスとかインスタンスとかの続きである『イニシャライザ』についてやっていきましょう。

『イニシャライザ』は単純に説明すると「インスタンス生成のときに必ず実行してくれる処理」って感じになりますね。

これはSwiftに限らず、クラス機能がある言語ならば大体組み込まれている感じになります。他の言語では『コンストラクタ』なんて名前が付いている事が多いですね。動作も似たようなものになります。

ちなみに『イニシャライザ』の事を『コンストラクタ』と呼んでしまっても個人的にはOKだと思ってます。Swiftでは『イニシャライザ』って呼ばれる事が多いようですが、言語によって呼び名が違う事は結構ありますので細かいことを気にしない精神こそ肝要でございます。

さて、ではさっそくちょちょいとクラスを定義してみましょう。以下のクラスの中の処理は定数『s』に文字列『初音ミク』を代入して、そんでもってメソッド『f』でその内容を出力するというシンプルな内容になってます。

class Test {
    let s = "初音ミク"

    func m() {
        print(s)
    }
}

さて、クラスの定義が終わったので中身を実行させてみましょう。中身を実行させるためにはインスタンスを作る必要がありますので生成してあげます。そしたらそのインスタンスの中のメソッド『m』を実行するようにします。

class Test {
    let s = "初音ミク"

    func m() {
        print(s)
    }
}

let testA = Test() // インスタンスを作ります。

testA.m() // 『初音ミク』が出力されます。

ここまでは大丈夫でしょうか。

そしたら前回やった内容をちょっと振り返ってみましょう。

クラスは「設計図のようなもの」というお話でしたね。「設計図のようなもの」なのでその設計図を元にしたインスタンスはいくらでも作ることができます。

というわけで以下のサンプルを見て下さい。クラス『Test』を元にした『testB』というインスタンスを作ってみました。

class Test {
    let s = "初音ミク"

    func m() {
        print(s)
    }
}

let testA = Test() // インスタンスを作ります。

testA.m() // 『初音ミク』が出力されます。

let testB = Test() // もういっちょインスタンスを作ります。

こんな感じでいくらでもインスタンスを生成できる、というのがクラスの強力なところです。

しかし、上記のサンプルを確認してみるとインスタンスを沢山作る意味があんまりないですよね。全部『初音ミク』という文字列が出力されるだけなので変化がありません。

class Test {
    let s = "初音ミク"

    func m() {
        print(s)
    }
}

// 以下は同じ処理なので複数のインスタンスを作る意味はあんまりないです。
let testA = Test() // インスタンスを作ります。

testA.m() // 『初音ミク』が出力されます。

let testB = Test() // もういっちょインスタンスを作ります。

testA.m() // 『初音ミク』が出力されます。

なんだかインスタンスを作るときにちょっと違った形で生成できれば話が変わってきそうです。ちょうど関数に引数を渡して実行して違う結果を出すようなイメージですね。

func test(s: String) {
    print(s)
}

// このように渡した引数によって結果が変わるようなイメージです。
test(s: "初音ミク") // 『初音ミク』が出力されます。
test(s: "Lily") // 『Lily』が出力されます。

そこで登場するのが『イニシャライザ』です。『イニシャライザ』はインスタンスを生成するときに必ず実行されるメソッド(処理)になりますので、これを利用することでそれぞれ違うインスタンスを作成することができます。

というわけで試してみましょう。以下のサンプルを見て下さい。

class Test {
    let s: String

    init() { // ここが『イニシャライザ』です。
        s = "初音ミク"
    }

    func m() {
        print(s)
    }
}

上記の『init(){}』という部分に注目です。これが『イニシャライザ』に該当します。

記述方法は「『init』という名前のついたメソッド(関数)」って感じなので普段書いている関数やメソッドと同じように行いたい処理を『{}』の中に記述すればOKです。

ちなみに『func init(){}』といったように『func』を付けてはダメなのでご注意です。

class Test {
    let s: String

    func init() { // 『func』は付けなくてOKです。エラーになっちゃいます。
        s = "初音ミク"
    }

    func m() {
        print(s)
    }
}

そんでもって、『init』という識別子(名前)の関数とかメソッドを作ると怒られますのでこちらも注意するようにして下さい。

func init() { // 『init』という名前の関数とかは作れません。

}

そしたら『イニシャライザ』の中に注目してみましょう。『s = "初音ミク"』となっていますので上記の処理はインスタンスを生成するたびに定数『s』に『初音ミク』が入ります。

class Test {
    let s: String

    init() { // ここが『イニシャライザ』です。
        s = "初音ミク"
    }

    func m() {
        print(s)
    }
}

let testA = Test() // 『インスタンス』を生成します。

testA.m() // 『初音ミク』が出力されます。

let testB = Test() // 『インスタンス』を生成します。

testB.m() // 『初音ミク』が出力されます。

さて、『イニシャライザ』を使ってみたはいいものの、まだ『tastA』、『testB』ともに『初音ミク』と出力されるだけのインスタンスになっちゃってますね。

ここで『イニシャライザ』で引数を受け取って、その値を定数『s』に代入するよう変更してみましょう。以下の処理を見てみて下さい。

class Test {
    let s: String

    init(str: String) { // 『イニシャライザ』で引数を受け取ります。
        s = str
    }

    func m() {
        print(s)
    }
}

let testA = Test(str: "初音ミク") // 引数を渡しつつインスタンスを生成します。

上記のサンプルの『Test(str: "初音ミク")』ってところに注目してみましょう。このようにクラスの生成時に記述する『()』の中には引数を記述することができ、その引数は『イニシャライザ』で受け取ることができます。受け取った部分は上記のサンプルだと『init(str: String)』ってところになりますね。引数の書き方は関数のときと同じです。

この仕組みを使えばインスタンス生成ごとに処理を出し分けできそうですね。というわけで以下が完成形です。違う処理が実現できていますね。

class Test {
    let s: String

    init(str: String) { // 『イニシャライザ』で引数を受け取ります。
        s = str
    }

    func m() {
        print(s)
    }
}

let testA = Test(str: "初音ミク") // 引数を渡しつつインスタンスを生成します。

testA.m() // 『初音ミク』が出力されます。

let testB = Test(str: "Lily") // 引数を渡しつつインスタンスを生成します。

testB.m() // 『lily』が出力されます。

クラス定義のときに引数を書く『()』の場所ですが『class クラス名(){}』って形じゃなく、『()』を書くのは『イニシャライザ』の部分になります。ここ、こんがらがりやすいところなんで注意です。

class Test() { // 『()』はここに書いちゃダメです。

}

class Test {
    init() { // 『()』は『イニシャライザ』に書きます。
    }
}

Swiftの文法ではクラスを定義するときに『イニシャライザ』を記述することは必須ではありません。

ただ、クラスの中の変数とか定数とかのプロパティに何も入れてあげないようにするとコンパイルが通りません。以下の処理を見てみて下さい。

class Test {
    var n: Int

    init() {
        n = 1
    }
}

上記の処理はクラス『Test』の中に変数『n』をInt型で定義して、『イニシャライザ』の中でその変数『n』に『1』を代入しているという処理ですね。

この『init(){}』の中身で変数『n』に何も代入してあげない、という形にするとばしっとエラーになります。

class Test { // エラーです。
    var n: Int

    init() {

    }
}
class Test { // エラーです。
    var n: Int
}

上記の処理の変数『n』に初期値を設定してあげればエラーはおきません。

class Test { // OKです。
    var n: Int = 1 // 初期値を設定してあげます。

    init() {

    }
}
class Test { // OKです。
    var n: Int = 1 // 初期値を設定してあげます。
}

なので「イニシャライザを省略するときはクラスの中の各プロパティに初期値を用意しておかないとNG」となんとなく覚えておくようにすると良いかもです。

クラスの中で使う『イニシャライザ』は、関数やメソッドと同じように外部引数名を使ったりオーバーロードさせたりすることができます。こんな感じですね。

class TestA {
    let s: String

    init(miku _s: String) { // 外部引数名を使用します。
        s = _s
    }

    func m() {
        print(s)
    }
}

let testA = TestA(miku: "初音ミク") // 『初音ミク』が出力されます。

testA.m() // 『初音ミク』が出力されます。

class TestB {
    var n = 0, s = "初音ミク"

    // 以下の『init(){}』はオーバーロードさせています。
    init(_n: Int) { // 引数が『_n』だったらこっちです。
        n = _n
    }

    init(_s: String) { // 引数が『_s』だったらこっちです。
        s = _s
    }

    func m() {
        print(n)
        print(s)
    }
}

let testB1 = TestB(_n: 10)

testB1.m() // 『10』と『初音ミク』が出力されます。

let testB2 = TestB(_s: "Lily")

testB2.m() // 『0』と『Lily』が出力されます。

これ、結構使用される機会が多いので覚えておくようにして下さい。

※外部引数名についてはこちらへ。

※オーバーロードについてはこちらへ。

というわけで『イニシャライザ』については以上になります。

次の記事では「関数とクラスの違い」についてやっていきたいと思います。ではではこの辺で。またお会いしましょう。

この記事は桜舞が執筆致しました。

著者が愛する小型哺乳類

桜舞 春人 Sakurama Haruto

ISDN時代から様々なコンテンツを制作しているちょっと髪の毛が心配な東京在住のプログラマー。生粋のロングスリーパーで、10時間以上睡眠を取らないと基本的に体調が悪い。好きなだけ寝れる生活を送るのが夢。ゲームとスポーツと音楽が大好き。誰か髪の毛を分けて下さい。

記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。