Angel Garcia
Angel Garcia

Reputation: 1577

buttons and labels resetting when scrolling through collection view

I have a collection view in which each cell possess the ability to be interacted with by the user. Each cell has a like button and a number of likes label. When the button is pressed, the button should turn cyan, and the label (which holds the number of likes) should increment. This setup currently works. However, when I scroll through the collection view and scroll back, the button reverts to its original color (white) and the label decrements down to its original value. I have heard of an ostensibly helpful method called prepareForReuse(), but perhaps I'm not using it correctly. Here is my code:

Here is the array which holds all the cells

var objects = [LikableObject]()

Here is the class definition for these objects

class LikableObject {

  var numOfLikes: Int?
  var isLikedByUser: Bool?

  init(numOfLikes: Int, isLikedByUser: Bool) {
    self.numOfLikes    = numOfLikes
    self.isLikedByUser = isLikedByUser
  }
}

Mind you, there is more functionality present in this object, but they are irrelevant for the purposes of this question. One important thing to be noted is that the data for each cell are grabbed using an API. I'm using Alamofire to make requests to an API that will bring back the information for the numOfLikes and isLikedByUser properties for each cell.

Here is how I load up each cell using the collection view's delegate method:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ObjectCell", for: indexPath) as! ObjectCell
    cell.configureCell(
      isLikedByUser: objects[indexPath.row].isLikedByUser!,
      numOfLikes:    objects[indexPath.row].numOfLikes!,
    )
    return cell
  }

The ObjectCell class has these three fields:

var isLikedByUser: Bool?
@IBOutlet weak var numOfLikes: UILabel!
@IBOutlet weak var likeBtn: UIButton!

And that configureCell() method, which belongs to the cell class, is here:

public func configureCell(numOfLikes: Int, isLikedByUser: Bool) {
    self.isLikedByUser   = isLikedByUser
    self.numOfLikes.text = String(numOfLikes)
    if isLikedByUser {
      self.likeBtn.setFATitleColor(color: UIColor.cyan, forState: .normal)
    } else {
      self.likeBtn.setFATitleColor(color: UIColor.white, forState: .normal)
    }
  }

And lastly, the prepareForReuse() method is here:

override func prepareForReuse() {
    if isLikedByUser! {
      self.likeBtn.setTitleColor(UIColor.cyan, for: .normal)
    } else {
      self.likeBtn.setTitleColor(UIColor.white, for: .normal)
    }
  }

This doesn't work. And even if it did, I still don't know a way to keep the numOfLikes label from decrementing, or if it should anyway. I'm speculating that a big part of this problem is that I'm not using the prepareForReuse() method correctly... Any help is appreciated, thank you.

Upvotes: 0

Views: 953

Answers (3)

Shehata Gamal
Shehata Gamal

Reputation: 100503

Currently all of this is good , the only missing part is cell reusing , you have to reflect the changes in the number of likes to your model array

class ObjectCell:UICollectionViewCell {

   var myObject:LikableObject!
}

In cellForRowAt

cell.myObject = objects[indexPath.row]

Now inside cell custom class you have the object reflect any change to it , sure you can use delegate / callback or any observation technique

Upvotes: 0

MongoTheGeek
MongoTheGeek

Reputation: 294

The prepareForResuse isn't needed here.

You do need to update the model underlying the tableview. One way to verify this is with mock data that is pre-liked and see if that data displays properly.

Upvotes: 0

farzadshbfn
farzadshbfn

Reputation: 2748

prepareForReuse is not the place to modify the cell, as the name states, you "only" have to prepare it for reuse. if you changed something (for example isHidden property of a view), you just have to change them back to initial state.

What you should do though, you can implement didSet for isLikedByUser inside the cell, and apply your modifications to likeBtn in there. (this is of-course the fast solution)

Long solution: It's an anti-pattern that your cell has a property named isLikedByUser, TableViewCell is a View and in all architectures, Views should be as dumb as they can about business logic. the right way is to apply these modifications in configure-cell method which is implemented in ViewController.

If you feel you'll reuse this cell in different viewControllers a lot, at least defined it by a protocol and talk to your cell through that protocol. This way you'll have a more reusable and maintainable code.

Upvotes: 1

Related Questions