0

I'm having al lot of troubles when I have updated Xcode from 12 to 13.

**All the table view controllers are not yet working as before.**

Doing dome debug I have noticed that when the command: tableView.dequeueReusableCell is used to read the already instantiated cells, it get the wrong pointers.

Example, I have 3 cells, and the first time the command dequeueReusableCell create one pointer for each cell (self)

row: 0, cell: <andrea.TestCell: 0x7fc387f19320
row: 1, cell: <andrea.TestCell: 0x7fc388a07730
row: 2, cell: <andrea.TestCell: 0x7fc388a1c230

when I reload the table (to refresh the data), the pointers are swapped

row: 0, cell: <andrea.TestCell: 0x7fc388a1c230
row: 1, cell: <andrea.TestCell: 0x7fc387f19320
row: 2, cell: <andrea.TestCell: 0x7fc388a07730

So, since that I'm using internal class variables (see below cell_store_var), when the table is refresh all the stored variables inside the class are not yet aligned with their right position.

I did a lot of trials but without success, and I don't know how to update by App on Apple Store,

here the xcode project: table view (this is only an example to reproduce the issue)

thanks, Andrea

import UIKit

class ListController_test: UIViewController, UITableViewDataSource, UITableViewDelegate {
    var timer_3sec: Timer!
    
    @IBOutlet var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        

        timer_3sec = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(self.read_sensors), userInfo: nil, repeats: true)
        
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }
    
     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }
    
     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TestCell

         cell.refresh(index: indexPath.row)
         print("Loaded - IndexPathItem: \(indexPath.item), cell: \(cell.self)")
        
        return cell
    }
    
    //imposta l'altezza delle celle in modo dinamico in base al tipo di sensore
     func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            return 100
    }
    
    
    
    @objc func read_sensors () {
        self.tableView.reloadData()
    }
}

import UIKit

class TestCell: UITableViewCell {

    var cell_store_var : Int = 0
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var label2: UILabel!
    
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
    
    func refresh(index:Int) {
        
        cell_store_var = index + cell_store_var + 1
        print("index: \(index), cell_store_var: \(cell_store_var)")
        
        let self_address = String(format:"%02X", self.hashValue)
        
        label.text = "index: \(index), cell_store_var: \(cell_store_var)"
        label2.text = "pointer: 0x\(self_address)"
    }

}

Andruino
  • 11
  • 4
  • 1
    Using the pointer of a cell is bad idea. You shouldn't rely on it. A cell is a cell. Could you explain why you need it? – Larme Jan 06 '22 at 12:46
  • hello, thanks for the answer, I'm not using directly the pointer, I have understood the issue looking the self pointer. For each cell class, I'm using internal variables, because for each cell row I read a sensor state (logic 0 or 1) and with a UIswitch I compare the old value with the new one (when I execute the switch action, I read the old switch value from an array and I compare it) – Andruino Jan 06 '22 at 13:03
  • I think it wasn't working in Xcode 12 to – Cy-4AH Jan 06 '22 at 13:06
  • hello, for example, if you put a slider on the cell, and if you update one of it with the value (sliding it) when you refresh the table (reload) the updated value will move on the other cells. Try it: https://drive.google.com/file/d/1SF1Ei2eLAdccTVbQaW_ORIBzcmga4dvY/view?usp=sharing Thank a lot! – Andruino Jan 06 '22 at 13:22
  • 2
    Trying to identify the cells by pointer is totally wrong. Primarily the cell is a view to display stuff stored in the data source. All actions to send to and receive data from the cell are supposed to be performed in the method `cellForRowAt`, also and in particular actions to respond to user interaction and to update the data source. The location to compare and process data is the model, the data source array. Consider also that cells are reused and being deallocated when going off screen. – vadian Jan 06 '22 at 13:26
  • You can create array of cells and use it in `cellForRowAt` instead of `dequeueReusableCell` – Cy-4AH Jan 06 '22 at 14:17
  • Having "bad pointers" as you describe IS NOT AN ERROR. It works as designed. I think that you are really misunderstanding how works the UITableView API and its reuse logic. So, instead could you share a code with your real issue, with your slider for instance? This way we might see how you handle the model, the view, and the "discussion between the two". – Larme Jan 07 '22 at 06:52
  • hello, thanks for your feedbacks. On my App, there are different lists used to show some logic state related to appliances (imagine as on/off light state). These values has to be refreshed every 1 second. On the list the user can also change its state pressing a switch. In my code I have managed the switch actions inside the CellClass using also some internal var (inside the CellClass) to remember the previous switch state. – Andruino Jan 08 '22 at 18:23
  • The current problem is that with Xcode13 when I reload the table (to refresh their value), the pointers are changed so I will lose this data (swap between the cells), and this create a lot of problems. How I can manage it? Where has to be the switch actions, inside the CellClass or in the table view? (consider that I'm using these CellClass inside different table views). I'm sure that I'm following a wrong architecture, and so I need some inputs from you. This is my AppStore list to see the lists used: https://apps.apple.com/it/app/andruino-app-wired-wireless/id651556267#?platform=iphone – Andruino Jan 08 '22 at 18:24

1 Answers1

1

I have solved my issue.
I used tableview.visibleCells to refresh the already allocated cells.
I have not yet used tableview.reloadData() that allocates again all the rows updating the pointers and so removing/resetting all the internal local variables used to store the cell operations. (for example to store the previous sensor value)
With this approach, to refresh the Cells, I use only the method update_cella() used to refresh the data.

func refresh_cells(){

        let cells = tableView.visibleCells
        for cell in cells {
            
            switch cell
                {
                case is CellaSwitchXIB:
                    let cell1 = cell as! CellaSwitchXIB
                    cell1.update_cella()
                    break
                case is CellaSensoreXIB:
                    let cell1 = cell as! CellaSensoreXIB
                    cell1.update_cella()
                    break
                case is CellaButtonXIB:
                    let cell1 = cell as! CellaButtonXIB
                    cell1.update_cella()
                    break
                case is CellaBlindXIB:
                    let cell1 = cell as! CellaBlindXIB
                    cell1.update_cella()
                    break
                case is CellaPwmXIB:
                    let cell1 = cell as! CellaPwmXIB
                    cell1.update_cella()
                    break
            default:
                   break
                }
            
        }
    }

Image of tableview

Andruino
  • 11
  • 4