テーブルビューのセルのビューモデルを作成するという設計上の決定に固執しています。各セルのデータは、データソースクラスによって提供されます(Contacts
の配列を持っています)。 MVVM
では、ビューモデルのみがモデルと通信できますが、すべてのセルのデータにアクセスできるようになるため、データソースをビューモデルに配置しても意味がありません。また、データソースを配置することも間違っていますデータへの参照があってはならないため、View Controllerで。他にもいくつかの重要な瞬間があります。
cellForRowAtindexPath
は、UI参照を含んではならないため、ビューモデルに配置しないでください。MVVM
の関係にあるセルのデータソースを「挿入」する正しい方法は何ですか?ありがとう。
いくつかの理論から始めましょう。 MVVMは、MicrosoftのSilverlightおよびWPFの プレゼンテーションモデル (またはアプリケーションモデル)の特殊化です。このUIアーキテクチャパターンの背後にある主なアイデアは次のとおりです。
利点はあなたが言ったとおりです:
質問に戻ると、UITableViewDataSource
プロトコルの実装は、UIフレームワークへの依存関係のため、アーキテクチャのビュー部分に属します。コードでそのプロトコルを使用するには、そのファイルがUIKitをインポートする必要があることに注意してください。ビューを返すtableView(:cellForRowAt:)
などのメソッドもUIKitに大きく依存しています。
次に、Contacts
の配列、つまり実際にモデルが、ビュー(データソースなど)を介して操作またはクエリできません。代わりに、ビューモデルをTable View Controllerに渡します。最も単純なケースでは、2つのプロパティがあります(計算されたプロパティではなく、保存することをお勧めします)。それらの1つはセクションの数であり、もう1つはセクションごとの行の数です。
var numberOfSections: Int = 0
var rowsPerSection: [Int] = []
ビューモデルはモデルへの参照で初期化され、初期化の最後のステップとして、これら2つのプロパティの値を設定します。
View Controllerのデータソースは、Viewモデルのデータを使用します:
override func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.numberOfSections
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.rowsPerSection[section]
}
最後に、セルごとに異なるビューモデル構造を作成できます。
struct ContactCellViewModel {
let name: String
init(contact: Contact) {
name = contact.name ?? ""
}
}
UITableViewCell
サブクラスは、その構造体の使用方法を知っています。
class ContactTableViewCell: UITableViewCell {
var viewModel: ContactCellViewModel!
func configure() {
textLabel!.text = viewModel.name
}
}
各セルに対応するビューモデルを作成するために、Table Viewビューモデルはそれらを生成するメソッドを提供し、ビューモデルの配列を設定するために使用できます。
func viewModelForCell(at index: Int) -> ContactCellViewModel {
return ContactCellViewModel(contact: contacts[index])
}
ご覧のとおり、ここでビューモデルはモデル(Contacts
配列)と通信する唯一のものであり、ビューはビューモデルとのみ通信します。
お役に立てれば。