Github
全体図
プロトコルではなくジェネリクスでModelを切り替える。
クラスの継承関係はViewとViewModelの連携を担うLinkViewControllerは、Modelのジェネリクスを保持します。Modelをジェネリクス化することで、Viewとロジック(Model)を分けたのですが、ジェネリクスはextensionをサポートせず、BaseViewControllerの下で定義する必要がありました。
BaseViewController << LinkViewController << 継承元ViewController
ViewControllerの基本クラスの継承方法
LinkViewControllerのジェネリクスにModelクラスを指定することで、LinkViewControllerはメンバ変数にViewModelを保持するようになり、ViewModelはメンバ変数にジェネリクスで定義したModelを保持します。
ViewとModelの関係
UIKitのControllerは上の階層のControllerがインスタンスを管理します。そのため、UIViewController、UINavigationController、
UITabBarControllerは限定的なスコープで生きる必要があり、内部変数のクラスに処理を委譲する構成にする必要がありました。
また、同じUIViewControllerを一部のタブや、上の階層のUINavigationで、使用するケースが想定されます。全ての画面に共通の通知を行なった場合、同じ通知を受け取るとどちらに向けた通知なのか識別できなくなります。
Modelの通知形式は、自分の親や、子供の1人にピンポイントで通知を行う必要があります。
UIViewControllerの構成をEnum管理する。
VCStructureIndexはUIViewControllerやUINavigationControllerの構成を示しています。UINavigationControllerの構成の中に他のVCStructureIndex、の構成を取り入れることを可能にしています。
generateVCメソッドがView、Modelまたは、他のViewのModelへの双方向バインドを可能にする、
PVLinkableなインスタンスを生成します。PVLinkableはUIViewControllerの、要件を満たしているため独立したUIViewControllerの生成でもあります。
また、Protocol Oriented ProgrammingでUIViewController、UINavigationController、UITabBarControllerで共通のメソッドを汎用化しています。
ViewModel
ViewとViewModel、ViewModelとModelの連携はインスタンスを比較して、対象のクラスにしか届かないようにする必要があります。
一部通知では、Enumの属性に同じEnumを指定できるようにしています。
これは例えば、自分のControllerから見て、親や、特定の子供向けに、さらにその場所から見た相対的な通知を柔軟に送ることを可能にしています。
ModelはViewControllerの処理タイミングも制御する。
Viewにも基本クラスのViewDidLoadがあり、また、ModelにもViewの基本クラスから送られるViewDidLoadがあります。
レイアウト(UIKit)に関わる対応はView、それ以外のAPI呼び出しや、Viewを制御する上で表示タイミングを制御したい場合は、ModelのViewDidLoadを使用するように考えています。