Let’s talk about cells baby!

Nowadays, we have a problem in iOS. Instead of MVC design pattern, which stands for Model-View-Controller, we have a disease called Massive-View-Controller.

As a good “refactoring skill”, we quickly adopted the MVVM (Model-View-ViewModel) design pattern. It is really good, no question about it, but let’s see one of the most common errors inside iOS — working with cells , UITableViewCells and UICollectionViewCells precisely, and the reason why we found ourselves infected by that “massive” virus.

Let’s say we want to present users inside our collection view:

struct User {    
var name: String
var imageUrl: String
}

We define our collection view cell like this:

class UserCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var profileImageView: UIImageView!
}

Inside our view controller, which has our collection view, we will have:

class UsersViewController: UIViewController {     
var users = [
User(name: "Djuro", imageUrl: "some_url"),
User(name: "Alfirevic", imageUrl: "some_other_url")
]
} 
extension UsersViewController: UICollectionViewDataSource {     

func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
{
return users.count
}
  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UserCell", for: indexPath) as! UserCollectionViewCell
let user = users[indexPath.row]
    cell.nameLabel.text = user.name                           
    cell.profileImageView.loadImageFrom(user.imageUrl)         

return cell
}
}

And there, we have a problem. Three lines of code, instead of just one. Imagine that we add descriptionLabel and dateLabel. Two more lines of code added. So five lines instead of one.

The one would say why? Why is that a problem? It’s not a big deal, right?

Let’s think about it: I am a view controller and I have a collection view. Of course, I know that my collection view has some cells — but hey I don’t care what’s going to be presented inside those cells. Why would I care? Configuring collection view cells is not part of my job at all! Exactly, good decomposition is a must!

Let’s see how we can fix this:

class UserCollectionViewCell: UICollectionViewCell {     
@IBOutlet private weak var nameLabel: UILabel!
@IBOutlet private weak var profileImageView: UIImageView!
var user: User! {
didSet {
nameLabel.text = user.name
      profileImageView.loadImageFrom(user.imageUrl)               
      descriptionLabel.text = user.shortBio            
      dateLabel.text = user.dateOfBirth        
}
}
}

First, why we declared our outlets to be private — well, no one should know about them actually. Anyone who is using this cell should know that it only has to provide a user and cell with configure itself accordingly.

Let’s see our “infected” view controller:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UserCell", for: indexPath) as! UserCollectionViewCell
cell.user = users[indexPath.row]
return cell
}

What do you think? At some point, we update our cell with some new labels, buttons, image views but the view controller would say: “Hey cell, I don’t care, here is your user object, configure yourself however you want.” And so, step-by-step, our code in view controllers will eventually get smaller — you know the one “less code, less bugs”.

Also, there are more examples where our view controller shouldn’t be involved at all and I will cover those of course. That is why MVVM is so powerful design pattern in the first place.

Happy coding!

Like what you read? Give Djuro Alfirevic a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.