Reputation: 10580
I have a TableView that allows user to add cells for text entry.
I implemented textfield delegate method that watches the change in the cell's textfield and store the text value in array.
I currently assign indexPath.row
of cellForRowAtIndexPath method as a tag value of cell's textfields. And I use that tag as the index of array for updating values.
But this approach causes issue once I delete some cells and add new cells to store new value. Values get stored in random index of array.
How do I save values in array in the same index order as the table cell even after some cells are deleted?
var stepCount = 1
var stepOrder = ["1"]
var steps = [""]
@IBAction func stepTextFieldDidChange(sender: UITextField) {
steps[stepTextField.tag] = sender.text!
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell?
if tableView == self.stepTableView {
let aCell = tableView.dequeueReusableCellWithIdentifier("StepCell", forIndexPath: indexPath) as! StepCell
stepTextField = aCell.getTextField()
stepTextField.tag = indexPath.row
aCell.stepTextField.delegate = self
aCell.configureStepCell(stepOrder[indexPath.row], step: steps[indexPath.row])
cell = aCell
}
return cell
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if tableView == stepTableView {
if editingStyle == .Delete {
// Delete the row from the data source
if stepOrder.count > 1 {
steps.removeAtIndex(indexPath.row)
stepTableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
stepTableView.reloadData()
}
} else if editingStyle == .Insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
}
@IBAction func addStep(sender: AnyObject) {
stepCount++
stepOrder.append("\(stepCount)")
steps.append("")
stepTextField.becomeFirstResponder()
stepTableView.reloadData()
}
Upvotes: 1
Views: 1914
Reputation: 115041
Using tags is difficult because, as you have found out, the index will change as you manipulate the table data.
Although it is a bit of overhead for a simple string, I would create a Step
class and store an array of these. Then you can store a reference to the Step
instance in your custom cell and update it from your delegate method.
On the subject of the delegate, you should move the UITextField
delegate method into your cell class and provide a new protocol to let your view controller know about the change.
class Step {
var stepValue = ""
convenience init(_ value:String) {
self.init()
self.stepValue=value
}
}
protocol StepDelegate {
func stepValueChanged(step:Step, newValue:String) -> Void
}
In your cell class you will have:
var delegate : StepDelegate?
var step: Step!
func stepTextFieldDidChange(sender: UITextField) {
self.step.stepValue = = sender.text!
self.delegate?.stepValueChanged(self.step,newValue:self.step.stepValue)
}
In your view controller you will have:
var steps = [Step]()
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell?
if tableView == self.stepTableView {
let aCell = tableView.dequeueReusableCellWithIdentifier("StepCell", forIndexPath: indexPath) as! StepCell
let step=self.steps[indexPath.row]
aCell.delegate=self
aCell.step=step
aCell.configureStepCell(step)
cell = aCell
}
return cell
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if tableView == stepTableView {
if editingStyle == .Delete {
// Delete the row from the data source
steps.removeAtIndex(indexPath.row)
stepTableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
} else if editingStyle == .Insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
}
@IBAction func addStep(sender: AnyObject) {
let newStep=Step("\(self.steps.count+1)")
let newPath=NSIndexPath(forRow: self.steps.count, inSection: 0)
steps.append(newStep)
self.stepTableView.insertRowsAtIndexPaths([newPath], withRowAnimation: .Automatic)
}
func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
if (self.steps.count > 1) {
return .Delete
} else {
return .None // Don't allow deletion of the last item in the table
}
}
Upvotes: 1