[iOS] StoryboardからのViewController生成時にDIを行う(外部ライブラリ不使用)
はじめに
こんにちは。平屋です。
StoryboardからViewControllerを生成するタイミングでDI(Dependency Injection、依存性の注入)を行う実装を試してみましたので紹介します。
本記事で紹介する実装では、iOS 13で追加されたメソッドを使用しています。
検証環境
- macOS Big Sur 11.4
- Xcode Version 12.5.1
(1) 生成される側のViewControllerの実装例
class DetailViewController: UIViewController { // (1-4) @IBOutlet weak var label: UILabel! // (1-1) let value: String override func viewDidLoad() { super.viewDidLoad() // (1-5) label.text = value } // (1-2) init?(coder: NSCoder, value: String) { self.value = value super.init(coder: coder) } // (1-3) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
本サンプルでは、String
を渡してViewControllerを生成してみます。
(1-1) プロパティを定義する
ViewController生成時に渡される値を保持するためのプロパティを定義します。値はイニシャライザの引数として渡されるので、このようにlet
、非オプショナルでプロパティを定義できます。
(1-2) イニシャライザを定義する
イニシャライザの引数の1つはNSCoder
型にし、呼び出し側から渡されたNSCoder
を使ってsuper.init(coder:)
を呼ぶようにします。
その他の引数は、対象画面で必要なものを定義します。本サンプルでは、2つ目の引数としてString
型の引数を定義し、渡された値を(1-1)のプロパティに設定しています。
(1-3) init?(coder:)
を追加する
(1-2) のイニシャライザを追加すると、init?(coder:)
の実装が必要になるので、追加します。
(1-4)、(1-5) プロパティを使用する
後は、値を使用する処理を追加します。本サンプルでは、UILabel
に値を設定しています。
(2) ViewController生成の実装例
class ViewController: UIViewController { @IBAction func detailButtonDidTap(_ sender: Any) { let storyBoard = UIStoryboard(name: "Main", bundle: nil) // (2-1) let controller = storyBoard.instantiateViewController(identifier: "DetailViewController") { coder in return DetailViewController(coder: coder, value: "Test") } // (2-2) navigationController?.pushViewController(controller, animated: true) } }
(2-1) ViewControllerを生成する
本サンプルでは、iOS 13で追加されたinstantiateViewController(identifier:creator:)を使用して、ViewControllerを生成しています。creator
引数で指定するクロージャ内では、(1-2)のイニシャライザを使用しています。
Storyboard上のInitialViewControllerを生成する場合は以下のメソッドを使用できます。
(2-2) ViewControllerを使用する
(1)で作成したViewControllerを使用する処理を追加します。