Reputation: 2196
I am having trouble putting a checkmark for a cell. I have placed a checklabel in the cell. When the user taps the cell the label displays ● and when the user taps the cell again it should display ○. However when I tap on a cell for example index path 0,10, then both 0,10 and 0,5 displays ●. Why does this happen? Any help is appreciated.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if isEditingSetlist{
if let cell = booklistDetailTableView.cellForRow(at: indexPath) as? BooklistTableViewCell {
if cell.checkLabel.text == "●"{
cell.checkLabel.text = "○"
}else{
cell.checkLabel.text = "●"
}
}
selectedRows.append(indexPath.row)
}
}
Upvotes: 0
Views: 163
Reputation: 924
UITableViewCell is a reference type. So when you will change UILabel value inside the cell, it would be applied for all other references. To avoid this problem, you can use an array.
Try this code Example:
ViewController.swift file
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
@IBOutlet weak var tavleView: UITableView!
var items: [Book]?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let item = items?[indexPath.row] {
item.isCheck = !item.isCheck
tableView.reloadRows(at: [indexPath], with: .none)
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? BooklistTableViewCell {
if let item = items?[indexPath.row] {
if !item.isCheck {
cell.checkLabel.text = "○ \(item.isCheck) \(indexPath.row)"
}else{
cell.checkLabel.text = "● \(item.isCheck) \(indexPath.row)"
}
}
return cell
}
return UITableViewCell()
}
override func viewDidLoad() {
super.viewDidLoad()
items = (0..<20).map({ _ in Book(false) })
tavleView.delegate = self
tavleView.dataSource = self
tavleView.reloadData()
}
}
BooklistTableViewCell.swift file
import UIKit
class BooklistTableViewCell: UITableViewCell {
@IBOutlet weak var checkLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Book.swift file
import Foundation
class Book {
var isCheck = false
init(_ isCheck: Bool) {
self.isCheck = isCheck
}
}
Upvotes: -1
Reputation: 5729
You can also change the checkmark in willDisplayCell
. This is an ideal place to change the appearance of a cell, just before it will be rendered. From the docs:
A table view sends this message to its delegate just before it uses cell to draw a row, thereby permitting the delegate to customize the cell object before it is displayed. This method gives the delegate a chance to override state-based properties set earlier by the table view, such as selection and background color. After the delegate returns, the table view sets only the alpha and frame properties, and then only when animating rows as they slide in or out.
So for your case, it could be something like:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if cell.checkLabel.text == "●" {
cell.checkLabel.text = "○"
} else {
cell.checkLabel.text = "●"
}
}
Upvotes: 1
Reputation: 285069
Cells are reused. The most efficient solution is to add an isSelected
property to the data model for example
struct Model {
var isSelected = false
// other properties
}
In cellForRowAt
set the checkmark accordingly (dataSource
represents the data source array)
let item = dataSource[indexPath.row]
cell.checkLabel.text = item.isSelected ? "●" : "○"
In didSelectRow
toggle isSelected
and reload the row (which calls cellForRowAt
)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if isEditingSetlist{
dataSource[indexPath.row].isSelected.toggle()
tableView.reloadRows(at: [indexPath], with: .automatic)
}
}
And forget selectedRows
. Extra arrays become annoying if cells can be inserted, deleted or moved.
Upvotes: 6
Reputation: 14397
In didSelect method just append and remove index path from array ... if that indexPath already exist ... remove that from array ... otherwise append.. then reload tableView
And in your cellForRow method check if that indexPath exists in selectedRows array put "●"
otherwise put "○"
to cell.checkLabel.text
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedRows.contains(indexPath.row) {
//remove it from array
if let index = selectedRows.index(where: { $0 == indexPath.row }) {
selectedRows.remove(at: index)
}
}else {
selectedRows.append(indexPath.row)
}
tableView.reloadData()
}
Upvotes: 1