LoginSignup
23
10

More than 3 years have passed since last update.

MicroViewControllerのInjectableとInteractableプロトコルを使ってみたら良かった話

Last updated at Posted at 2019-08-29

最近少し入力が多くて画面が多く複雑な画面を実装することになったので、iOSDC2018で発表されてたMicroViewControllerを思い出して、ViewController間のやりとりを入力と出力のプロトコルで縛る方式で行うようにした。

「MicroViewControllerのやり方良いよね」というと、正しく相手に通じないかもしれないので何が良いかというのを書いておこうと思います。私は別にButtonとかCellとかをViewControllerにしたいわけじゃなくて、単に入力と出力のプロトコルが良いよね、コンセンサスとりやすいよね、これをベースとさせてもらって自分で好きにやっていけば良いよねということが私の感想です。

全体的なイメージ

この話のサンプルとして次の4つのViewControllerを考えました

  • 何かを編集する目的のある画面のちょっと複雑なEditViewController
    • 2パターンの値を編集する画面で2パターン切り替える画面のEditValueContainerViewController
    • 値を編集するコンテナの中のEditViewController
  • 値を計算したりするCalcViewViewController

MicroViewController.001.png

入力

public protocol Injectable {
    associatedtype Input
    func input(_ input: Input)
}

サンプルとしてはEditValueContainerViewControllerからEditValueViewControllerに初期値を渡すような際にも使える。

class EditValueViewController: UIViewController {
    struct Input {
        let value: Int
    }

    ... 
}

extension EditValueViewController: Injectable {
    func input(_ input: Input) {
        // self.input = input として使い回すときもあるけどしなかったりもする
        if isViewLoaded {
            label.text = input.value
        }
    }
}

func input(_ input: Input)が単なるメソッドなのが良い。これをvar input: Inputにしてしまうと入力をgetできてしまう。

// プロパティだったらgetできるのでprintしてみる
print(viewController.input)

getして誰かが困るかっつうと困らない。困らないんだけど入力をgetする意味がないのでできない方が良くて、メソッドなのでセットしかできないのがいい。言い換えると、セットしかしないんだからセッターしかない。良い。

出力

public protocol Interactable {
    associatedtype Output
    func output(_ handler: ((Output) -> Void)?)
}

例えば、EditValueViewControllerがコンテナに結果を伝えたい

class EditValueViewController: UIViewController {
    struct Input {
        let value: Int
    }

    // OutputはInputと同じにもできる。つまり入力の型と出力の型は同じ
    typealias Output = Input
    private var outputHandler: ((Output) -> Void)?
    ... 

    func textFieldが入力されて値が変わったよ(_ changedValue: Int) {
        outputHandler?(Output(value: changedValue))
    }
}

extension EditValueViewController: Interactable {
    func output(_ handler: ((Output) -> Void)?) {
        outputHandler = handler
    }
}

これも入力と同じで出力がメソッドなのがいい。

その他の良い点

その他の良い点も書いておく。

  • そもそもこのprotocolはViewControllerに限定せずViewでも使えるのがいい
  • 複数人でも入力と出力だけやり方を揃えてぶらさず、そこを重点的にチェックすれば良くなるはず
  • また、入力と出力さえ公開されていればよくて他はすべてprivateでいい。人のコードをチェックする際に考えることが減りそうなのもいい
23
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
10