[Swift4] 任意の引数を受け取れるイニシャライザを持つUIViewController

By | 2018年7月7日

Swift で、クラスのプロパティを初期化する際にはイニシャライザコンストラクタ)を使用します。

UIViewController のプロパティを初期化する際、自作のイニシャライザ(init)を定義して任意の引数を設定したいという場合、少し特殊な書き方をします。

以下では、自作の init を定義した新しい UIViewController をボタンで起動するサンプルを紹介します。

サンプルのソースコード

Single View App のプロジェクトを新規作成し、生成される ViewController.swift を以下のように変更します。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let button = UIButton(type: .system)
        button.frame = CGRect(x: 100, y: 100, width: 100, height: 40)
        button.setTitle("Open", for: .normal)
        button.addTarget(self, action: #selector(self.openVC), for: .touchUpInside)
        self.view.addSubview(button)
    }

    @objc func openVC(_ sender: UIButton) {
        let newVC = NewViewController(text: "テキスト", value: 222)
        self.present(newVC, animated: true, completion: nil)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

class NewViewController: UIViewController {
    
    var text: String = ""
    var value: Int = 0
    
    // 任意の引数を取る自作のイニシャライザ
    init(text: String, value: Int) {

        // 受け取った引数でプロパティを初期化
        self.text = text
        self.value = value
        
        // クラスの持つ指定イニシャライザを呼び出す
        super.init(nibName: nil, bundle: nil)
    }
    
    // 新しく init を定義した場合に必須
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        print(text)
        print(value)
    }
}

これは、起動後に表示されるボタンをタップすると、任意の引数を渡した新しい UIViewController を起動し、渡した値をコンソールに表示するアプリです。

上記のコードでは、引数に文字列 "テキスト" と数値 222 を設定しているので、以下のようにコンソールが表示されます。

任意のイニシャライザ(init)を定義したクラス

ソースコードの詳細

NewViewController に、任意の引数を受け取ることのできるイニシャライザを定義しています。自作のイニシャライザでは、そのクラスが元々持つ指定イニシャライザ(Designated Initializer)を中で呼び出す必要があります。

// 任意の引数を取る自作のイニシャライザ
init(text: String, value: Int) {

    // 受け取った引数でプロパティを初期化    
    self.text = text
    self.value = value
    
    // クラスの持つ指定イニシャライザを呼び出す
    super.init(nibName: nil, bundle: nil)
}

また、同時に init?(coder aDecoder: NSCoder) を定義することも必須です。このイニシャライザの中には特に処理を記述する必要はありません。

// 任意の引数を取る自作のイニシャライザ
init(text: String, value: Int) {

    // 受け取った引数でプロパティを初期化
    self.text = text
    self.value = value
    
    // クラスの持つ指定イニシャライザを呼び出す
    super.init(nibName: nil, bundle: nil)
}

// 新しく init を定義した場合に必須
required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

以上、任意の引数を受け取れるイニシャライザの定義方法です。

自作のイニシャライザが優先的に呼び出されるようにする

インスタンス化の際に引数を空にした場合に、自作のイニシャライザを呼び出されるようにするには convenience を使ったイニシャライザを定義します。

...

// 任意の引数を取る自作のイニシャライザ
init(text: String, value: Int) {

    // 受け取った引数でプロパティを初期化
    self.text = text
    self.value = value
    
    // クラスの持つ指定イニシャライザを呼び出す
    super.init(nibName: nil, bundle: nil)
}

// 新しく init を定義した場合に必須
required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

convenience init() {
    self.init(text: "initial", value: 1)
}

...

これによって NewViewController()NewViewController(text: "initial", value: 1) と同じになります。

参考

Initialization — The Swift Programming Language (Swift 4.2)

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*