Error: "Unexpected nil index path in _canPerformAction:forCell:sender:, this should never happen." - swift

I have a dynamic tableView with 2 prototype cells. I am using one of the cells for section header, the section header cell has it's own class. Data have been populated to these cells without problems.
I am getting this error message "Error: “Unexpected nil index path in _canPerformAction:forCell:sender:, this should never happen.” at runtime when I tap on the section header. Anyone knows how to get rid of this error? Thanks in advance!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MachineTableViewCell") as! MachineTableViewCell
if self.uptime.count == self.machines.count {
cell.GPUNumber.text = self.allGPUNumber[indexPath.section][indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
guard let header = tableView.dequeueReusableCell(withIdentifier: "header") as? HeaderTableViewCell
else {
return nil
}
let machine = machine[section]
header.name.text = machine.name + " - " + machine.ip + ":" + machine.port
return header
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
return 124
}

I initially missed this as well but if you take a step back and look at the return type you almost kick yourself.
For a regular cell the return type is UITableViewCell.
However for the header it's UIView.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")...
///
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableCell(withIdentifier: "header")...
///
return header
}
Therefore, what you need to do is return the contentView.
return header.contentView

Related

tableview header and prototype cell showing wrong

Is there are reason why there are height differences between what is shown and what has been set as a height? also there is a space between header and prototype cell which I cannot get rid of.
extension FirstTabThirdView: UITableViewDataSource , UITableViewDelegate {
func tableView (_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = headerView
return view
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellOne", for: indexPath)
cell.textLabel?.text = "hello"
return cell
}
}

How to change editing style for specific cell in tableview

I have a tableview where the editingstyle is .delete for all the cells. But I want to have some specific cells that doesnt have editingstyle (so that you can't swipe them, .none). Anyone have any suggestions for how to implement this?
I tried to write something like UITableViewCell.EditingStyle.none for that specific row but that didnt work.
Thanks in advance, Pontus
Consider the following example:
class ViewController: UITableViewController {
private let arr = (1...10).map { "Item \($0)" }
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arr.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
cell?.textLabel?.text = arr[indexPath.row]
return cell ?? UITableViewCell()
}
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
if indexPath.row == 2 {//<- Your condition
return .none
} else {
return .delete
}
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
}
So the key is to use editingStyleForRowAt in order to change the style for a specific cell (or even multiple cells) (see the documentation for further reference: https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614869-tableview).

Scroll to bottom TableView with custom section and cell Swift

My tableview has custom sections and cells. Every time the user scroll to the bottom it will call the server and load additional datas. My problem is how do I detect the last section so it could load more data? Each section contain 1 to 3 rows. My willDisplay wasn't working properly and the refreshControl.beginRefreshing() indicator didn't show too. Thanks!
let refreshControl = UIRefreshControl()
//MARK - Header Sections
func numberOfSections(in tableView: UITableView) -> Int {
return tableData[segmentedControlIndex].count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "headerCell") as! HomeSectionTableViewCell
let model = events[segmentedControlIndex][section]
cell.setup(model: model)
.
.
.
return cell.contentView
}
//MARK - Cells
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData[segmentedControlIndex][section].rows.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "detailCell") as! HomeTableViewDetailCell
.
.
.
cell.detailTitleLabel?.text = tableData[segmentedControlIndex][indexPath.section].rows[indexPath.row].detailTitleLabelString
cell.detailSubtitleLabel?.text = tableData[segmentedControlIndex][indexPath.section].rows[indexPath.row].detailSubtitleLabelString
return cell
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.000001
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell: HomeTableViewDetailCell = tableView.cellForRow(at: indexPath) as? HomeTableViewDetailCell {
cell.detailTitleLabel?.numberOfLines = cell.detailTitleLabel?.numberOfLines == 0 ? 1 : 0
tableView.reloadData()
}
}
//MARK - TableView add more data
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.section == tableView.numberOfSections - 1 {
self.refreshControl.beginRefreshing()
self.page = self.page + 1
self.getMoreData() { result in
self.refreshControl.endRefreshing()
print("Load More Bets Data reload: \(result == true ? "Success":"Failure")")
}
}
}

tableview loading invisible rows as well , cellforrowat index path getting celled for hidden rows

Tableview loading invisible rows as well , cellForRowAtIndexPath getting celled for hidden rows
func numberOfSections(in tableView: UITableView) -> Int {
return ordersArray.count;
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let selectedOrder = ordersArray[indexPath.section]
return CGFloat(180 + (30 * selectedOrder.lineItems().count ));
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row == 1)
{
let deliveryShipChargesCustomCell =
tableView.dequeueReusableCell(withIdentifier: "DeliveryShipChargesCustomCell", for: indexPath) as! DeliveryShipChargesCustomCell
return deliveryShipChargesCustomCell;
}
else
{
let orderCustomCell = tableView.dequeueReusableCell(withIdentifier: "OrdersCustomCell" , for: indexPath) as! OrdersCustomCell
return orderCustomCell;
}
}
problem with this code snippet is that it gets load row that are not even visible for example if order array count is 10. and there are two rows in each section , initially tableview (_ tableView: UITableView, cellForRowAtIndexPath: IndexPath) gets called for 20 times.
Any thoughts?

tableview persisting cell image after reloading

I have a tableview with cells that when selected displays an image within the selected cell, this image then disappears when the cell is selected again, and so on. When i press a submit button the selected cells are remembered and the tableview reloads with new data. But when doing this all the new data loads but the selected cell image persists. I have tried calling tableView.reloadData() on the main queue but it still persists. The image also persists when i press the submit button several times.
Heres my code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currentQuestion.answers.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return tableView.frame.height/CGFloat(currentQuestion.answers.count)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
setSelectedArray()
let cell: AnswersTableViewCell = tableView.dequeueReusableCell(withIdentifier: "answersTableViewCell") as! AnswersTableViewCell
let text = currentQuestion.answers[indexPath.row]
let isAnAnswer = currentQuestion.answerKeys[indexPath.row]
cell.answerTextLabel.text = text
cell.answerView.backgroundColor = UIColor.white.withAlphaComponent(0.5)
cell.contentView.sendSubview(toBack: cell.answerView)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell: AnswersTableViewCell = tableView.cellForRow(at: indexPath) as? AnswersTableViewCell {
if cell.answerImageView.image == nil {
cell.answerImageView.image = UIImage(named: "paw.png")
selected[indexPath.row] = true
} else {
cell.answerImageView.image = nil
selected[indexPath.row] = false
}
}
}
#IBAction func submitButtonWasPressed() {
if questionNumber < questions.count - 1 {
questionNumber += 1
setCurrentQuestion()
self.answersTableView.reloadData()
self.view.setNeedsDisplay()
}
}
Any help would be great. Thanks
You need to set the image back to its correct value in cellForRow. Cells in your table are reused between calls to reloadData, and since you're not touching the imageView, it's keeping its previous value. Looks to me like you want:
cell.answerImageView.image = selected[indexPath.row] ? UIImage(named: "paw.png") : nil
inside of tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath).