ViewControllerのinit処理みなさんどうしていますか?
僕はだいぶイケテナイ呼び出しをしていたので、ちょっとまとめてみました。
1.viewControllerの呼び出し
ViewControllerって当たり前だけど呼び出したいですよね。
例えばユーザー画面とか作る時、こんな書き方をしてみました。
let viewController = UserViewController()
viewController.userId = userId
self.navigationController?.pushViewController(viewController, animated: true)
class UserViewController: UIViewController {
var userId:Int?
override func viewDidLoad() {
super.viewDidLoad()
//userを呼ぶAPIをかく
}
}
これでも動くは動くんですよ。
2.動くならいいじゃん何がダメなの?
例えば他でもユーザー画面に遷移したい!!って思った時
let viewController = UserViewController()
//viewController.userId = userId
self.navigationController?.pushViewController(viewController, animated: true)
これでもビルド通るんですよね。そうすると...
class UserViewController: UIViewController {
var userId:Int?
override func viewDidLoad() {
super.viewDidLoad()
// userを呼ぶAPIをかく
// user呼べないよおおおおおおおお!
}
}
ってなって初期表示の画面になっちゃうんですよね。
こんな感じで呼び出し方によって変わっちゃう動きはイケテナイ。
UserViewController呼ぶときは必須にしたいよねえ!
3.ViewControllerのinit書こうね
普通にinit処理書くこともできますが、便利なライブラリがあるので、それに頼ります。
https://github.com/tarunon/Instantiate
これを使って書くとこうなります
// 初期化時に必ずuserIdが必要なように書く
let viewController = UserViewController.instantiate(with: .init(userId:userId))
self.navigationController?.pushViewController(viewController, animated: true)
import Instantiate
import InstantiateStandard
class UserViewController: UIViewController, StoryboardInstantiatable {
//ここは初期化時の処理を書く
func inject(_ dependency: UserViewController.Dependency) {
self.userId = dependency.userId
}
//ここに必要な変数を書く
struct Dependency {
var userId:Int
}
var userId:Int!
override func viewDidLoad() {
super.viewDidLoad()
//userを呼ぶAPIをかく
//ここでは必ずuserIdが取れる!!!
}
}
このように書くことで
UserViewControllerを呼び出すときは必ずuserIdが必要なんだ!
とコード上で力強く宣言できます
4.まとめ
ViewControllerのinit処理を正しく入れると、ViewControllerの使い回しが大変楽になります。
呼び出し側に負担を求めるViewControllerを書くのはやめましょう。(自戒をこめて...)
ちなみに他にもCellやUIViewなどもほぼ同じ方法で、init処理書けます。
ライブラリを作っていただいた人に感謝。