dequeueReusableCell on tableView get wrong pointers on Xcode 13 - ios

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)"
}
}

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

Related

Label not appearing in Swift table

No data is appearing in my Swift table. I'm fairly new to Swift and not quite sure why this or what I might be missing. I followed the guide here for the most part with some differences:
Apple Table Creation
Here's the tableView definition:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "AccountTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? AccountTableViewCell else {
fatalError("The dequeued cell is not an instance of AccountTableViewCell.")
}
let item = userDataSource[indexPath.row]
// Dummy values just to test this out
cell.leftLabel.text = "test1";
cell.rightLabel.text = "test2";
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1;
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) ->Int {
return userDataSource.count;
// This should be an array value, but I have also tried passing a static int here as well to test
}
Here is my class definition with the implemented procotols:
class AccountViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
And here is my table cell definition:
class AccountTableViewCell: UITableViewCell {
//MARK: Properties
#IBOutlet weak var leftLabel: UILabel!
#IBOutlet weak var rightLabel: 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
}
}
I've got both rightLabel and leftLabel setup in the Storyboard.
I can go to the account page represented by this view controller and a table display does come up - it just has absolutely no data in it.
What am I missing?
It is not sufficient to simply add a UITableView to your view controller scene. You must set the tableview's dataSource property to your view controller instance in the Storyboard connections inspector for the tableview.

When scroll table view content change

i have custom table view cell that having rating stars. i'm using https://github.com/hsousa/HCSStarRatingView for rating View.
there is my code for table view and cell view.
class RatingTableViewCell: UITableViewCell {
var value : CGFloat = 0.0
#IBOutlet weak var starRatingView: HCSStarRatingView!
#IBOutlet weak var titleLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initStarRatingView()
starRatingView.addTarget(self, action: #selector(DidChangeValue(_:)), for: .valueChanged)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
private func initStarRatingView() {
var scalingTransform : CGAffineTransform!
scalingTransform = CGAffineTransform(scaleX: -1, y: 1);
starRatingView.transform = scalingTransform
starRatingView.emptyStarImage = #imageLiteral(resourceName: "strokStar")
starRatingView.halfStarImage = #imageLiteral(resourceName: "halfStar")
starRatingView.filledStarImage = #imageLiteral(resourceName: "fillStar")
starRatingView.allowsHalfStars = true
}
#IBAction func DidChangeValue(_ sender: HCSStarRatingView) {
self.value = sender.value
}
class RatingViewController: CustomViewController,UITableViewDelegate,UITableViewDataSource {
var values : [CGFloat] = [0.5,0.0,0.0,0.0,0.0,0.0,0.0]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RatingTableViewCell", for: indexPath) as! RatingTableViewCell
values[indexPath.row] = cell.value
cell.starRatingView.value = values[indexPath.row]
return cell
}
//MARK: _Table data source
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
values.count
}
}
there is a problem when i scroll table view. dequeue Reusable Cell data is wrong. how can update value data for each cell?
The problem is that you are storing the value in the cell. Take a look at those two lines:
let cell = tableView.dequeueReusableCell(withIdentifier: "RatingTableViewCell", for: indexPath) as! RatingTableViewCell
values[indexPath.row] = cell.value
You dequeue a cell and assign it's value to values[indexPath.row]. The problems that you are noticing when scrolling are caused by the fact that the reused cell was previously used for a different indexPath, which means that their value (that you assign to values[indexPath.row]) is meant for its previous indexPath.
To fix that, I would advise getting rid of the value variable in RatingTableViewCell. Instead, define a protocol RatingTableViewCellDelegate that will be used to inform the RatingViewController about the new value.

Retrieve textfield.text which is inside custom cell

I have tableview which has custom cells.
Each cell has 3 textfields: dayInWeek, startTime, endTime.
In below image, it has 2 rows. But user can click + button to add more rows.
If user click Submit button, I want to loop to every rows, collect 3 textfields data, and store in array or whatever.
Custom TableViewCell:
import UIKit
class RegularScheduleCell: UITableViewCell {
#IBOutlet weak var dayInWeek: UITextField!
#IBOutlet weak var startTime: UITextField!
#IBOutlet weak var endTime: UITextField!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
And a view controller:
import UIKit
class RegularScheduleVC: UIViewController, UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var numOfRow = 1
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numOfRow
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "RegularScheduleCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! RegularScheduleCell
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
numOfRow -= 1
self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.right)
tableView.reloadData()
}
}
func insertNewRow(_ sender: UIBarButtonItem) {
if numOfRow < 7 {
numOfRow += 1
tableView.reloadData()
}
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
tableView.setEditing(editing, animated: animated)
}
}
At this moment, I try to use UITextFieldDelegate
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "RegularScheduleCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! RegularScheduleCell
cell.dayInWeek.delegate = self
cell.startTime.delegate = self
cell.endTime.delegate = self
return cell
and
func textFieldDidEndEditing(_ textField: UITextField) {
allCellsText.append(textField.text!) //allCellsText is an array
print(allCellsText)
}
so that when user finish editing, then add that data to array.
However, this does not satisfy my requirement, because:
on the same cell: can not know if the data is belong to dayOfWeek, or startTime, or endTime
on 2 different cells: can not know if data is belong to, let say, dayOfWeek of 1st cell or dayOfWeek of 2nd cell.
Therefore, How can I loop to all cells, get all 3 text fields data?
Thanks
Method 1:
Make an array of key pairs as-
var arrayOfKeyPairs = [[String:Any]]()
arrayOfKeyPairs.append(["header":"xx",
"value" : "",
“id”: "dsd",
"order" : 0])
We are just replacing the default values with user input values as-
func textFieldDidEndEditing(_ textField: UITextField) {
let center: CGPoint = textField.center
let rootViewPoint: CGPoint = textField.superview!.convert(center, to: tableView)
let indexPath: IndexPath = tableView.indexPathForRow(at: rootViewPoint)! as IndexPath
arrayOfKeyPairs[indexPath.row ]["value"] = textField.text//here you are appending(replacing) data to array
}
On click of submit button, cross check what you received as-
func tapsOnNext(){
self.view.endEditing(true)//for adding last text field value with dismiss keyboard
print(arrayOfKeyPairs)
}
Method 2:
We can get cell data by accessing the cell with particular indexpath as
func tapsOnNext(){
let indexpath = IndexPath(row: 0, section: 0)
let cell = tableView.cellForRow(at: indexPath) as! CustomTableViewCell
print(cell.myTextField.text)
}
You can get text of UITextField with adding target to UITextField
cell.YOUR_TEXTFIELD.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
//EditingChanged is one of the events and will be fired whenever the user changes any character in that UITextField.
After that, you can call your function like this:
func textFieldDidChange(textField: UITextField) {
//your code
}
Don't forget to create class for UITableViewCell and to create IBOutlets of all your UITextField in that custom cell class
You can do it the following way.
First of all you can create an object for example "History"
make its properties like daysInWeek, startTime, endTime.
In your viewDidLoad method you define an array of Objects. Populate the data in the array, or save those objects of "History" that you created in this array.
Set the dataSource of the table view to this array.
in your method cellForRowAtIndexPath you can access the elements of the array you created above.
When you are tapping the plus button, you can create a new object of History, save this object in the array and reload the table view.
If you can share the git repo of this code, i will show how this is being done.
Simple code: On button click get cell data from cell's text field
let indexpath = IndexPath(row: 0, section: 1)
let cell = ItemtableView.cellForRow(at: indexPath) as! CustomTableViewCell
print("text \(cell.myTextField.text)")

UITableView doesn't scrolling while scrolling over the cell

I created a UITableView in a UIViewController from the storyboard and create custom tableViewCell class. Now when I run my project,
It is not scrolling when I touch any cell and move up/down.
BUT, it scrolls if I start scrolling with the either end of UItableViewCell (nearly, 15px of left inset).
I tried to create another fresh tableView, still not working.
I tried to create a tableViewController, still not working.
Then I think the code is NOT the cause of the issue.
Using Xcode 8.2.1
Below is my code work :
Class File
struct Quote {
var text: String
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView?
let cellIdentifier = "cell"
// Array of strings for the tableView
var tableData = [Quote(text: "zadz ad azd azds fsd gdsfsd"), Quote(text: "zakd gqsl jdwld bslf bs ldgis uqh dm sd gsql id hsqdl sgqhmd osq bd zao mos qd"), Quote(text: "azdhsqdl sb ljd ghdlsq h ij dgsqlim dhsqihdùa dbz ai ljsm oqjdvl isq dbvksqjld"), Quote(text: "dsqb jhd gs qdgsq dgsq u hdgs qli hd gsql i dgsq li dhs qij dhlqs dqsdsd.")]
override func viewDidLoad() {
super.viewDidLoad()
self.tableView?.register(UITableViewCell.self, forCellReuseIdentifier: self.cellIdentifier)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return number of rows in table
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Create Resusable Cell, get row string from tableData
let cell = tableView.dequeueReusableCell(withIdentifier: self.cellIdentifier)! as! cellClass
let row = indexPath.row
// Set the labels in the custom cell
cell.mainText.text = tableData[row].text
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Do what you want here
let selectValue = self.tableData[indexPath.row]
print("You selected row \(indexPath.row) and the string is \(selectValue)")
}
}
And this is my cellClass: (Custom cell)
class cellClass: UITableViewCell {
#IBOutlet weak var mainText: 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
}
}
Storyboard hierarchy of UITableView
You might be have some x-code issues because generally it never happens and I run your project it working properly as usually it works.
Below is code work I have done.
I'm not taking sturcture of array like you, I'm just doing with taking simple array.
my array is
arrayData = ["One", "Two", "three", "four"]
below is cellForRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : cellClass = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! cellClass
cell.lblstates.text = arrayData[indexPath.row]
return cell
}
If you facing any issue then let me know.
Check if the user interaction Enabled check of your cell is off or not in the storyboard
Resolved: I had to uninstall and install Xcode again..

Display the same content in UITableView included in custom UITableViewCell

I have an issue with UITableView inserted in a UITableViewCell. This is my custom cell:
Everything works fine for the first, second and third cells, but from the fourth cell for the content of the UITableView inserted in cell is used always the same rows of the first, second and third cells alternatively. Instead the labels outside the UITableView are correctly displayed in every cells. This is my code for the custom cell class:
import UIKit
class SimulazioneQuestionTableViewCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource {
let cellIdentifier = "simRisposteCell"
var arrayRisposte = [Risposta]()
#IBOutlet var numeroLabel: UILabel!
#IBOutlet var domandaLabel: UILabel!
#IBOutlet var risposteTableView: UITableView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
var nib = UINib(nibName: "SimulazioneQuestionAnswerTableViewCell", bundle: nil)
self.risposteTableView.registerNib(nib, forCellReuseIdentifier: self.cellIdentifier)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayRisposte.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as SimulazioneQuestionAnswerTableViewCell
cell.textLabel?.text = arrayRisposte[indexPath.row].testo
return cell
}
}
And this is my view controller:
import UIKit
class SimulazioneViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var areaSimulazione: Int = Int()
var arrayDomande = [Domanda]()
var arrayRisposte = [[Risposta]]()
var cellIdentifier = "domandaSimulazioneCell"
#IBOutlet var tempoTrascorso: UILabel!
#IBOutlet var simulazioneTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
arrayDomande = ModelManager.instance.getSimulazione(area: areaSimulazione)
var nib = UINib(nibName: "SimulazioneQuestionTableViewCell", bundle: nil)
self.simulazioneTableView.registerNib(nib, forCellReuseIdentifier: self.cellIdentifier)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayDomande.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: SimulazioneQuestionTableViewCell = simulazioneTableView.dequeueReusableCellWithIdentifier(self.cellIdentifier) as SimulazioneQuestionTableViewCell
var domanda: Domanda = arrayDomande[indexPath.row]
var rispXDomanda = ModelManager.instance.getAnswersForQuestion(domanda.numero)
cell.numeroLabel.text = String(domanda.numero)
cell.domandaLabel.text = domanda.testo
cell.arrayRisposte = rispXDomanda
return cell
}
Some advice to resolve this issue?
Thank you guys!
I never had the idea of putting a UITableView inside a UITableViewCell and therefore would have approached this from a different direction. I'm not saying the table inside a cell is impossible or a bad idea, but the following approach might actually be easier.
My understanding is that your table view shows a number of questions, and each question has possible answer right below it.
I'd use one section per question, with the first row using a custom cell that shows the numeroLabel and the domandaLabel (basically SimulazioneQuestionTableViewCell without the table), and then put the answers into the remaining rows for the section.
private let QuestionCellIdentifier = "QuestionCell"
private let AnswerCellIdentifier = "AnswerCell"
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return arrayDomande.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let rispXDomanda = ModelManager.instance.getAnswersForQuestion(domanda.numero)
return 1 + rispXDomanda.count // one extra for the question
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let domanda = arrayDomande[indexPath.section]
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier(QuestionCellIdentifier) as SimulazioneQuestionTableViewCell
cell.numeroLabel.text = String(domanda.numero)
cell.domandaLabel.text = domanda.testo
return cell
default:
let cell = tableView.dequeueReusableCellWithIdentifier(AnswerCellIdentifier) as SimulazioneQuestionAnswerTableViewCell
let rispXDomanda = ModelManager.instance.getAnswersForQuestion(domanda.numero)
cell.textLabel?.text = rispXDomanda[indexPath.row - 1].testo
return cell
}
It might be a good idea to cache the answers that you get from ModelManager. It depends on how expensive it is to get them - with the code above getAnswersForQuestion() will be called a lot.
Edit: I personally like the .Grouped style for the table view. Using a section per question will nicely separate them visually.

Resources