Reputation: 85
What I have: I have a CollectionViewCell as .xib + .swift files. Every cell gets their data from the database. Inside every cell I have a like button.
What I want: When I press the like button of a certain cell, I want to be able to read this data so I can change it and write the new data in the Database. So I want to change the like attribute of the dataset of a certain cell and save it in the DB
What I tried: I have the indexPath of the cell but how can I read the data of the cell?
@IBAction func likeButton(_ sender: UIButton) {
var superview = self.superview as! UICollectionView
let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:superview)
let indexPath = superview.indexPathForItem(at: buttonPosition)
print(superview.cellForItem(at: indexPath!))
// Change picture
if sender.currentImage == UIImage(systemName: "heart.fill") {
sender.setImage(UIImage(systemName: "heart"), for: .normal)
} else {
sender.setImage(UIImage(systemName: "heart.fill"), for: .normal)
}
}
UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCollectionViewCell.identifier,
for: indexPath) as! MyCollectionViewCell
cell.backgroundColor = .white
let newShoeCell = shoesArray?.randomElement()
// Fill cells with data
cell.imageView.image = UIImage(named: newShoeCell!.imgName)
cell.shoeTitle.text = newShoeCell!.title
cell.price.text = String(newShoeCell!.price)
cell.ratingNumberLabel.text = String(newShoeCell!.meanRating)
cell.floatRatingView.rating = newShoeCell!.meanRating
if newShoeCell!.liked {
cell.likeButtonOutlet.setImage(UIImage(systemName: "heart.fill"), for: .normal)
} else {
cell.likeButtonOutlet.setImage(UIImage(systemName: "heart"), for: .normal)
}
return cell
}
Upvotes: 0
Views: 528
Reputation: 131418
You need to change your thinking. It is not the data "of a cell" A cell is a view object. It displays information from your data model to the user, and collects input from the user.
You asked "...how can I read the data of the cell?" Short answer: Don't. You should be saving changes into your data model as you go, so once you have an index path, you should use it to index into your data model and get the data from there.
You need to figure out which IndexPath the tapped button belongs to, and fetch the data for that IndexPath from your data model.
If you look at my answer on this thread I show an extension to UITableView that lets you figure out which IndexPath contains a button. Almost the exact same appraoch should work for collection views. The idea is simple:
In the button action, get the coordinates of the button's frame.
Ask the owning table/collection view to convert those coordinates to an index path
Use that index path to fetch your data.
The only difference is that for collection views, the method you use to figure out which IndexPath the button maps to is indexPathForItem(at:)
instead of indexPathForRow(at:)
Upvotes: 2
Reputation: 234
I suggest you add a property to your cell
class MyCell: UITableViewCell {
var tapAction: (() -> Void)?
...
@IBAction func likeButton(_ sender: UIButton) {
tapAction?()
...
}
}
and set it in view controller
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
cell.tapAction = { [weak self] in
// call to database or whatever here and then reload cell
tableView.reloadRows(at: [indexPath], with: .automatic)
...
}
In general, cell should never care what its indexPath is, nor should it make calls to superview
Upvotes: 0