ViewModel for UITableView datasource in VIPER, swift

2k Views Asked by At

I am using VIPER architecture for my recent project. But I am wondering how to implement UITableView DataSource.

In VIPER, View is passive. They send event to Presenter, then Presenter send proper ViewData(ViewModel) to View.

So I stored ViewModels for tableView in View. (View doesn't ask data to Presenter.)

class View: UIViewController, UITableViewDataSource {
  var viewModels: [CellViewModelType] = []
  
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return viewModels.count
  }
  
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let viewModel = viewModels[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIndetifier", for: indexPath)
    cell.configure(with: viewModel)
    return cell
  }
}

When user selects item in tableView, View send didSelectItemAt event with indexPath to Presenter. Then Presenter decides proper action for event, push VC or fetch data.

So Presenter should know ViewData (or Real Data). Or Presenter pass event to Interactor, because Interactor stores Real Data.

Here is my dilemma for synchronization. Data is spread View, Presenter, Interactor. They may be different, because Real Data can be changed asynchronously in background (like chat app). Because locking would be entirely inappropriate, how do I assure stateful data integrity among multiple threads in a VIPER architecture?

Any help would be greatly appreciated. :D

2

There are 2 best solutions below

0
On

Am I right that you are afraid of inconsistency of data in ViewModels array and Data array in Presenter or Interactor? If so, when new data have been fetched by Interactor, it's passed to Presenter. There I prefer to synchronously send it to View as ViewModels first, then set it to Presenter's Data array. And when you call didSelectCellAtIndexPath: and send event with IndexPath to Presenter, additional checks in accessing data from Data array are a good idea.

0
On

A Presenter should store ViewModels and Interactor should store entities. So View should ask the presenter for ViewModels like so

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   let viewModel = presenter.getViewModel(at: indexPath.row)
   let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIndetifier", for: indexPath)
   cell.configure(with: viewModel)
   return cell
}

When user selects an item presentor can deside to call a method on the interactor. So module state is stored only in the Interactor and a view state is stored in the Presenter. View should not have any state