1

code:

I have added check box in my tableview cell design in storyboard

code: if there are 8 cells then if i select first cell then got blue_tick image in first cell and why in 5th cell also got blue_tick.. here i have selected only first cell..

in the same way if i select 2nd cell then 6th cell also got blue_tick why? where am i wrong

var selectedArray:[Int] = []

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

if tableView == self.tableView{
    
    let cell:PaymentCell = tableView.cellForRow(at: indexPath) as! PaymentCell
    if let indexData = eventListData?.result?.events?[indexPath.row] {
        
        if let index = selectedArray.firstIndex(of: indexData.id ?? 0) {
            
            cell.checkImg.image = UIImage(named: "checkbox_inactive")
            selectedArray.remove(at: index)
            
        } else {
            selectedArray.append(indexData.id ?? 0)
            cell.checkImg.image = UIImage(named: "blue_tick")
        }
    }
}
}

why for selecting one cell every 5th cell un unnecessarily also got blue_tick.. please do guide me got stuck here from long.. but didn't get solution till now

in cellForRowAt handled like this

var isfromDetails = false

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCell(withIdentifier: "PaymentCell", for: indexPath) as! PaymentCell

let indexData = eventListData?.result?.events?[indexPath.row]
cell.titleLbl.text = indexData?.event_title
cell.addressLbl.text = indexData?.event_venue

var floatVal: Float?
if let standardRate = indexData?.ticket_price,
   let convValue = eventListData?.result?.conversion_factor {
    let priceVal = Float(standardRate)
    let convVal = Float(convValue)
    
    floatVal = (priceVal * convVal!)
    
    if let floatVal = floatVal {
        let formatter = NumberFormatter()
        formatter.maximumFractionDigits = 2
        formatter.roundingMode = .down
        let roundedValue1: String = formatter.string(from: floatVal as NSNumber) ?? ""
        
        cell.priceLbl.text = "\(eventListData?.result?.user_curreny?.symbol ?? "GBP") \(roundedValue1)"
        
    } else {
        cell.priceLbl.text = "N/A"
    }
}
let bannerImage = indexData?.event_thumbnail ?? ""
cell.bannerImg.getImage(subUrl: eventListImageBaseUrl, withImagePath: bannerImage, placeHolder: #imageLiteral(resourceName: "icon8"))
cell.bannerImg.contentMode = .scaleAspectFit

if isfromDetails{
    let id = indexData?.id ?? 0
    if selectedArray.contains(id){
        cell.checkImg.image = UIImage(named: "blue_tick")
    }else{
        cell.checkImg.image = UIImage(named: "checkbox_inactive")
    }
}
return cell
}

class EventListCell: UITableViewCell {

@IBOutlet weak var checkImg: UIImageView!
override func awakeFromNib() {
    selectionStyle = .none
    super.awakeFromNib()
}
}

how to solve this unnecessary image in unwanted cell,

Note: if i put break point and debug then in cellForRow its not going inside if isfromDetails{ still blue_tick shoes why? and if i comment that code in cellForRow still blue_tick showes why?. And here id is not appending in arrSelectedRowsBuy but just blue_tick image showing in cell.

where am i wrong. please do guide me

new dev
  • 45
  • 7
  • 1
    It sounds like maybe you are scrolling the table view to reveal the other cells and, since cells are reused, what was the first cell is showing as the fifth cell. You need to configure the checkmark image (and any other state) in `cellForRowAt:`. – Geoff Hackworth May 12 '23 at 16:57
  • Does this answer your question? [UITableView Checkmarks disappear when scrolling](https://stackoverflow.com/questions/27918584/uitableview-checkmarks-disappear-when-scrolling). Lots of others in [these search results](https://stackoverflow.com/search?q=uitableview+scroll+checkmark). – HangarRash May 12 '23 at 18:00
  • @HangarRash, I have edited my post with `cellForRowAt` i dont understand the reason for unnecessary check mark.. here the unnecessary check position depends on iPhone size like in small devices its begens from 5th cell in big devices its begun from 6th cell.. i dont understand the reason.. and am using custom chk box – new dev May 12 '23 at 18:42
  • Your `cellForRowAt` will only show the correct checkmark if `isfromDetails` is `true`. Is it? – HangarRash May 12 '23 at 19:16
  • Your code only sets the check image if `isFromDetails` is `true`. The very first line of the code you have posted appears to have a property with it set to `false`. So when cells are reused whatever checkmark was last used for that cell (when it was for a different row) will be unchanged. Why does `isFromDetails` even exist? Are you trying to reuse this view in multiple places with different behaviour (one where checking rows is possible, one where it isn’t?) – Geoff Hackworth May 13 '23 at 07:52
  • @GeoffHackworth, yes if i remove `isFromDetails` then working for now but the problem is we are using stack of viewcontrolers while push and pop so if not that particular viewcontroller then i dont need the check box selected. but anyway for now this is working. – new dev May 13 '23 at 09:48
  • If you are using that variable to control whether selection is available or not then you also need to use that variable in `didSelectRowAt` to *not* set different images. The two methods need to behave consistently with each other. – Geoff Hackworth May 13 '23 at 09:50

1 Answers1

1

The reason is quite clear:

Cells are reused, but – for performance reasons - the states of the UI elements are not reset to a default state. Therefore you have to make sure that all UI elements are set to a defined state in cellForRowAt.

In this case if isfromDetails is false the state of cell.checkImg.image is undefined. A reasonable solution is to merge all if statements into one.

The cell will show a checkmark if isfromDetails is true, id does exist and selectedArray contains the id

if isfromDetails, let id = indexData?.id, selectedArray.contains(id) {
   cell.checkImg.image = UIImage(named: "blue_tick")
} else {
   cell.checkImg.image = UIImage(named: "checkbox_inactive")
}

I highly recommend to drop selectedArray and maintain the selected state in the data model.

And why ist everything optional (eventListData?.result?.events?[indexPath.row])? The data source of an existing non-optional table view should be non-optional.

vadian
  • 274,689
  • 30
  • 353
  • 361
  • actually i tried this way as well.. but the problem is if i select first cell and scroll to up to bottom and scroll down to top then selected cell vanishes – new dev May 13 '23 at 07:05
  • Then there is something wrong with your `selectedArray` and/or the huge amount of optionals. As mentioned both is bad practice anyway. – vadian May 13 '23 at 08:20
  • I’m not sure how we can explain it any clearer what is going wrong. Table cells are reused when scrolling (or reloading) so whatever image was set for that cell when it was in a different row will still be there unless `cellForRowAt` overwrites it. You have said the code inside the `if isfromDetails{` in that method is not being executed. So the image is not being reset according to the new row position. That variable needs to be `true`, the `if` test removed (so always set the check image), or the whole variable removed if it is not needed. – Geoff Hackworth May 13 '23 at 09:08