I have implemented a checkbox in UITableView controller, it works perfectly but when the checkbox are selected and the rows in the tableview are deleted and the when I add a new row to the tableview it gets selected.
Here is a link to my project: https://files.fm/f/tepkz2du
I think it has something to do with when a row is delete, the index path is messed up.
UPDATED CODE:
cellForRowAt:
if let btnChk3 = cell?.contentView.viewWithTag(100) as? UIButton {
btnChk3.addTarget(self, action: #selector(checkboxClicked(_ :)), for: .touchUpInside)
}
if let btnChk2 = cell.contentView.viewWithTag(22) as? UIButton {
btnChk2.isSelected = UserDefaults.standard.integer(forKey: myarray[indexPath.row]) == (indexPath.row + index) ? true : false
}
checkboxClicked
let defaults = UserDefaults.standard
let myarray = defaults.stringArray(forKey: "ScheduleArray") ?? [String]()
if sender.tag == 100 {
if let btnChk2 = cell.contentView.viewWithTag(22) as? UIButton {
if btnChk2.isSelected == true {
btnChk2.isSelected = false
UserDefaults.standard.set(-1, forKey: myarray[(indexPath?.row)!] )
UserDefaults.standard.synchronize()
}else{
btnChk2.isSelected = true
UserDefaults.standard.set((indexPath?.row)! + index, forKey: myarray[(indexPath?.row)!])
UserDefaults.standard.synchronize()
}
}
sender.isSelected = false
}
editingStyle == .delete:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
if tableView == ScheduleTableView{
let defaults = UserDefaults.standard
var myarray = defaults.stringArray(forKey: "ScheduleArray") ?? [String]()
print(myarray)
myarray.remove(at: indexPath.row)
defaults.set(myarray, forKey: "ScheduleArray")
ScheduleTableView.deleteRows(at: [indexPath], with: .fade)
}
}
Don't save index path in UserDefaults , save any value which you are showing in table cell. And match it with array in cellForRowAtIndex . like I did
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let c = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! tabCell
c.lblC.text = arry?[indexPath.row]
/* for example
arry = ["First","Second","Third","Fourth","Fifth","Sixth","Seventh","eight","Ninth","Tenth"]
seleted = ["First","Fifth"]
*/
print("indexpath--",indexPath.row)
if selected != nil
{
if (selected?.contains((arry?[indexPath.row])!))!
{
c.btnCheck.setBackgroundImage(#imageLiteral(resourceName: "check.png"), for: .normal)
}
else
{
c.btnCheck.setBackgroundImage(#imageLiteral(resourceName: "uncheck.png"), for: .normal)
}
}
c.btnCheck.tag = indexPath.row
c.btnCheck.addTarget(self, action:#selector(btnCheckClick(btn:)) , for: .touchUpInside)
return c
}
I am not able to run your code ...
thats way I made my demo
check it, hope you can get an idea...
https://files.fm/u/hj7jz9dj
if let btnChk2 = cell.contentView.viewWithTag(22) as? UIButton {
btnChk2.isSelected = UserDefaults.standard.integer(forKey: myarray[indexPath.row]) == (indexPath.row + index) ? true : false
}
CHANGE IN cellForRowAt
let defaults = UserDefaults.standard
let myarray = defaults.stringArray(forKey: "ScheduleArray") ?? [String]()
if sender.tag == 100 {
if let btnChk2 = cell.contentView.viewWithTag(22) as? UIButton {
if btnChk2.isSelected == true {
btnChk2.isSelected = false
UserDefaults.standard.set(-1, forKey: myarray[(indexPath?.row)!] )
UserDefaults.standard.synchronize()
}else{
btnChk2.isSelected = true
UserDefaults.standard.set((indexPath?.row)! + index, forKey: myarray[(indexPath?.row)!])
UserDefaults.standard.synchronize()
}
}
sender.isSelected = false
}
CHANGE IN checkboxClicked
You could use func prepareForReuse()
method in the UITableViewCell to make sure the checkbox is unselected when you insert a new row.
You store in userdefaults the value of the checked button according to its indexpath. The problem with this attitude is when you delete the cell, the new cell is getting the indexpath of the previous cell which is wrong.
You should work with a model to represent your rows. Store in the "ScheduleArray" an object instead of just a string.
Something like that:
struct myRow {
var title: String = ""
var isSelected: Bool = false
}