Why not make the ViewModel the table view’s data source?

Last week, after watching the first video of the Beginning Swift course, Christina asked:

Why not make the ViewModel the table view’s data source?

First, some context: we built a single view app with a table view using the MVVM pattern, and the table view’s data source is the ViewController, not the ViewModel.

So what do you think? Why shouldn’t we make the ViewModel the table view’s data source? That seems to make a lot more sense – the ViewModel has all the data anyway, so why shouldn’t it be the data source?

Here’s what I told Christina:

Great question. I prefer not to make the ViewModel the table view’s data source because I think the data source should be part of the View layer, rather than the ViewModel layer. Mainly because there’s UI stuff in the data source – it has to create and return a UITableViewCell, for example. My rule of thumb is that if a class starts with “UI”, it shouldn’t be in the ViewModel.

The problem with making the ViewModel the table view’s data source is that it starts to blend the layers together and we lose the separation between them. The View should be separate from the ViewModel – that’s exactly the definition of MVVM. And the table view’s data source is part of the View, so of course we don’t want it to be part of the ViewModel.

But wait – is the table view data source really part of the View?

Its name (UITableViewDataSource) implies that it’s part of a different layer – maybe the Model or ViewModel, right? I mean, a DataSource certainly doesn’t belong in the View layer, does it?

Does it?

Check out the following methods (all from UITableViewDataSource):

numberOfSectionsInTableView(_ tableView: UITableView) -> Int

tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int

tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell

What do they all have in common?

Each and every one of these – and all the other methods in the protocol – have the UI prefix somewhere in their signature. In every single method, one of the parameters is a UITableView, and that’s most certainly part of the View. And on top of that, tableView:cellForRowAtIndexPath: requires us to create and configure a UITableViewCell – and that most definitely belongs in the View layer. (Even if you’re using MVC.)

To summarize:

  1. The table view’s data source requires UI code
  2. Therefore, the table view data source is part of the View layer
  3. Therefore, the ViewModel shouldn’t be the table view’s data source

And remember, if a class starts with “UI”, it belongs in the view.