Reputation: 6471
I tried the following code for getting custom cell.This code I used for the purpose of UITableView cell Check ONLY ONE Row at a Time.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// if they are selecting the same row again, there is nothing to do, just keep it checked
if ((seleectedIndex) != nil) {
if indexPath == seleectedIndex {
return
}
let oldCell = tableView.cellForRow(at: seleectedIndex!) as! MisstageTableViewCell
if oldCell.accessoryType == UITableViewCellAccessoryType.checkmark {
oldCell.accessoryType = UITableViewCellAccessoryType.none
oldCell.buttonSelection.setImage(UIImage(named:"off")?.withRenderingMode(.alwaysOriginal), for:.normal)
}
}
// toggle old one off and the new one on
let newCell = tableView.cellForRow(at: indexPath) as! MisstageTableViewCell
if newCell.accessoryType == UITableViewCellAccessoryType.none {
newCell.accessoryType = UITableViewCellAccessoryType.checkmark
newCell.buttonSelection.setImage(UIImage(named:"on")?.withRenderingMode(.alwaysOriginal), for:.normal)
}
seleectedIndex = indexPath // save the selected index path
}
My code is working fine.But When I scroll the table view (like up and down)then I clicked on any cell then I got the crash on the specific line
let oldCell = tableView.cellForRow(at: seleectedIndex!) as! MisstageTableViewCell
I don’t know what is the reason for crashing.Could you please help me to resolve the issue?
Upvotes: 0
Views: 378
Reputation: 12023
You should not change the cell data inside didSelectRow
, ideal solution would be to reload the rows based on selected indexPath and check/unckeck
accessory type for the cell
class TableViewController: UITableViewController {
var selectedIndex: IndexPath?
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MisstageTableViewCell
if let selectedIndex = selectedIndex, indexPath.row == selectedIndex.row {
cell.accessoryType = .checkmark
let image = UIImage(named: "on")
cell.buttonSelection.setImage(image!.withRenderingMode(.alwaysOriginal), for: .normal)
} else {
cell.accessoryType = .none
let image = UIImage(named: "off")
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//selected the same indexPath then return
if let selectedIndex = selectedIndex, selectedIndex == indexPath {
return
}
if let selectedIndex = selectedIndex, selectedIndex != indexPath {
let oldSelectedIndex = selectedIndex
selectedIndex = indexPath
tableView.reloadRows(at: [oldSelectedIndex, indexPath], with: .fade)
} else {
selectedIndex = indexPath
tableView.reloadRows(at: [indexPath], with: .fade)
}
}
}
Upvotes: 1
Reputation: 924
why are you updating the cell inside
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
You should do it in
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
First declare a variable as:
var selectedIndexPath: IndexPath!
didSelectRowAt should be modified as follows:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedIndexPath != nil {
let tempIndexPath = selectedIndexPath
selectedIndexPath = indexPath
tableView.reloadRows(at: [indexPath, tempIndexPath], with: .fade)
}
else {
selectedIndexPath = indexPath
tableView.reloadRows(at: [selectedIndexPath], with: .fade)
}
}
I don't know what you are doing in cellForRowAt. But it should be modified as follows:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.accessoryType = UITableViewCellAccessoryType.none
cell.buttonSelection.setImage(UIImage(named:"off")?.withRenderingMode(.alwaysOriginal), for:.normal)
if selectedIndexPath != nil && indexPath == selectedIndexPath {
cell.accessoryType = UITableViewCellAccessoryType.checkmark
cell.buttonSelection.setImage(UIImage(named:"on")?.withRenderingMode(.alwaysOriginal), for:.normal)
}
return cell
}
Upvotes: 1
Reputation: 28
The result of tableView.cellForRow(at: seleectedIndex!) returns is optional, so it`s can be nil
Upvotes: 0
Reputation: 1551
You are force unwrapping an optional. If you select a cell then scroll and the selected cell is no longer on screen the system can remove it from memory and thus it will become nil.
if let oldCell = tableView.cellForRow(at: seleectedIndex!) as? MisstageTableViewCell {
// do stuff here
}
Upvotes: 0