Search code examples
iosswiftuitableviewreusability

UIbutton currentTitle in cell reused Swift


Currently i have an uitableview with a custom cell. It contains an uilabel and uibutton - data source for which is fetched from two separate arrays. The uibutton function is to append the corresponding array with lines for the uilabel and insert them in the uitableview as well as add a new cell with another uibutton below.

There is one conditional - once the question array value is nil, the answer uibutton is shown.

The issue is - because the uibutton name is fetched as the last value from the array, once i scroll all the button titles are being re-written to match the latest one.

Here is the flow. enter image description here

Here is my code

 func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return numberofsections
// is always equal to zero
} 


func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

return someTagsArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell     {

    var cell:TblCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! TblCell

        cell.lblCarName.text = someTagsArray[indexPath.row]
        cell.act1.setTitle(answersdict.last, forState:UIControlState.Normal)


return cell
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {

var cell:TblCell = cell as! TblCell

    if let text = cell.lblCarName.text where text.isEmpty {
        cell.act1.hidden = false
    } else {
        println("Failed")
    }
}

Is there any way to store those uibutton values or prevent the cell from being reused completely.

Some more data on my question\answer model I have a dictionary with the nested array called linesmain for questions

linesmain = ["first":["question 1", "question 2", "question 3"], "answer 1": ["question 1", "question 2", "question 3"], "answer 2": ["question 1", "question 2", "question 3"], "answer 3":["question 1", "question 2", "question 3"]]

and a similar dictionary for answers

answersmain = ["first": ["answer 1"], "answer 1": ["answer 2"], "answer 2": ["answer 3"], "answer 3":["answer 4"]]

i keep it that way because i might increase the amount of answers in the future.

Then i have two arrays for the cells to append. One appends - the questions (someTagsArray), another one - the answers (answersdict). On launch the "first" questions and answers are loaded, then depending on the uibutton currentTitle in the newly appended cell.

Thank you.


Solution

  • No, there's no way to prevent a cell from being reused. Reuse keeps memory requirements low, and scrolling fast, as the table only keeps around enough cells to ensure it can show the rows that are visible.

    Cells will constantly be reused as you scroll back and forth. This is normal, expected, and isn't meant to be circumvented.

    You're going to have to store those answer values in your model in a way that you can lookup the answer by indexPath row.

    Change answersdict.last to use some method that takes a row, and returns the answer text for that row.

    If you're not sure how to do that, you'll need to post more code showing how your model stores your question and answer data.

    Update

    In general, there are a few things I'd do differently, that you might want to consider.

    1. A tableView cell is selectable. Instead of adding buttons to the cell, you could just let the user selecting (tapping) a cell accomplish the work of the button event.

    2. As the answer to your original question suggested, you'd be better off dividing the data into sections, with each section containing the questions and answer for that section:

        Section 0
            Question 1 // row 0 of section 0
            Question 2 // row 1 of section 0
            Question 3
            Answer 1
        Section 1
            Question 1 // row 0 of section 1
            Question 2 // row 1 of section 1
            and so forth...
    

    Your someTagsArray would be better off stored like [[question 1, question 2, question 3],[question 1, question 2, question 3], ...]. You see how each set of questions is in its own (section) array?

    Then you can get the text for each question by querying someTagsArray[indexPath.section][indexPath.row] and the text for each answer by querying answersArray[indexPath.section].

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return someTagsArray.count
    } 
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return someTagsArray[section].count + 1 // number of Questions + 1 for the answer
    }
    

    Update 2:

    Do you see the example of how the data is broken down into sections? Let's look at the counts for the first section, which is section 0:

    someTagsArray[0].count // 3 questions in section 0
    answersArray[0] // the one answer for section 0
    

    The count of questions and answers aren't equal. As you pointed out, that would make no sense.

    So, now that we see there are 3 questions and 1 answer for section 0, we know that section 0 has 4 rows.

    The first three rows are for the questions. The last row is for the answer.

    So, in tableView:cellForRowAtIndexPath, you're going to have to examine indexPath.row, and determine whether it is a question row or the answer row. It should be fairly easy to do, and I'll leave that as an exercise.