Issue in tableview cell selection and deselection using button in swift

61 Views Asked by At

code: in this code i have already selected cells ids in selectedRows once i reach the vc those cells are showing as selected and if i select and deselect the cells then getting correct values in array selectedRows and getting wrong names in selectedNamesArray why? initially when adding selected names in array then also mismatch in names indexes. where ami wrong?

class ViewController2: UIViewController {
@IBOutlet weak var tableView: UITableView!

var selectedRows = [32, 38, 89, 11]
var selectedNamesArray: [String] = []

var arrayModel: [SampleModel] = [SampleModel(id: 32, name: "Apple"),
                                 SampleModel(id: 38, name: "Smasung"),
                                 SampleModel(id: 22, name: "Black berry"),
                                 SampleModel(id: 76, name: "Nokia"),
                                 SampleModel(id: 12, name: "Real me"),
                                 SampleModel(id: 75, name: "Lenova"),
                                 SampleModel(id: 36, name: "Pocco"),
                                 SampleModel(id: 11, name: "Motorola"),
                                 SampleModel(id: 37, name: "Infinix"),
                                 SampleModel(id: 88, name: "China"),
                                 SampleModel(id: 89, name: "Jio")
]

override func viewDidLoad() {
    super.viewDidLoad()
    
    if !selectedRows.isEmpty{
        selectedNamesArray = arrayModel
            .filter { selectedRows.contains($0.id) }
            .map { $0.name }
    }
    print("existing names: \(selectedNamesArray) \n and ids: \(selectedRows)")
}
}

extension ViewController2: UITableViewDelegate, UITableViewDataSource{

func numberOfSections(in tableView: UITableView) -> Int {
    2
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
        return arrayModel.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    let cell = tableView.dequeueReusableCell(withIdentifier: "TestTableviewCell1", for: indexPath) as? TestTableviewCell1
    cell?.selectionStyle = .none
    cell?.titleLbl?.text = arrayModel[indexPath.row].name
    cell?.checkBtn.tag = indexPath.row
    
    cell?.isChecked = selectedRows.contains(arrayModel[indexPath.row].id)
    
    cell?.buttonAction = { [self] sender in
        
        if selectedRows.contains(arrayModel[indexPath.row].id) {
            if let indexToRemove = selectedRows.firstIndex(of: arrayModel[indexPath.row].id) {
                
                selectedRows.remove(at: indexToRemove)
                
                if indexToRemove < selectedNamesArray.count {
                    selectedNamesArray.remove(at: indexToRemove) // Remove corresponding name
                }
                //   selectedNamesArray.remove(at: indexToRemove) // Remove the corresponding name
                cell?.isChecked = false
            }
        } else {
            selectedRows.append(arrayModel[indexPath.row].id)
            selectedNamesArray.append(arrayModel[indexPath.row].name) // Add the corresponding name
            cell?.isChecked = true
        }
        print("Selected rows: \(selectedRows)")
        print("Selected names: \(selectedNamesArray)")
    }
    return cell!
}
}

class TestTableviewCell1: UITableViewCell{

@IBOutlet weak var titleLbl: UILabel!
@IBOutlet weak var checkBtn: UIButton!
var isChecked = false{
    didSet{
        checkBtn.backgroundColor = isChecked ? .blue : .green
    }
}
var buttonAction: ((_ sender: AnyObject) -> Void)?
@IBAction func buttonPressed(_ sender: UIButton) {
    self.buttonAction?(sender)
}
}

struct SampleModel{
var id: Int
var name: String
}

o/p:

existing names: ["Apple", "Smasung", "Motorola", "Jio"] and ids: [32, 38, 89, 11] //here also indexes are not matching with both array values

after doing some selection de selection

Selected rows: [32, 38, 89, 36] Selected names: ["Apple", "Smasung", "Motorola", "Pocco"] //agin mis match in indexes

2

There are 2 best solutions below

0
DonMag On BEST ANSWER

When you filter an array, you get back an array in the same order as the original array.

So, let's simplify things a little...

var arrayModel: [SampleModel] = [
    SampleModel(id: 32, name: "Apple"),
    SampleModel(id: 76, name: "Nokia"),
    SampleModel(id: 11, name: "Motorola"),
    SampleModel(id: 89, name: "Jio"),
]

var selectedRows = [11, 76]

let a1 = arrayModel.filter { selectedRows.contains($0.id) }
        
print("selectedRows:")
print(selectedRows)

print()

print("Filtered:")
print(a1)
        

We get this output in the debug console:

selectedRows:
[11, 76]

Filtered:
[App.SampleModel(id: 76, name: "Nokia"), App.SampleModel(id: 11, name: "Motorola")]

Seems like it's "out of order"?

The .filter closure essentially says:

create a new, empty returnArray

then, loops through arrayModel with:

is element.id in selectedRows?
if yes, append element to returnArray

With the above code, we get:

32 / Apple    -- discard
76 / Nokia    -- append
11 / Motorola -- append
89 / Jim      -- discard

The order of the returned array doesn't care about the order of selectedRows ... it's just checking if .id is contained in selectedRows, so the order is:

["Nokia", "Motorola"]

If you want to do something with the "names" in the order they were selected you'll need to sort selectedNamesArray to match the order of selectedRows.

Or, instead of trying to maintain a selectedNamesArray throughout, create it when you want to do something with it, like this:

var selectedNamesArray: [String] = []
        
selectedRows.forEach { i in
    if let m = arrayModel.first(where: { $0.id == i }) {
        selectedNamesArray.append(m.name)
    }
}

print(selectedNamesArray)

outputs:

["Motorola", "Nokia"]
5
Chandaboy On

Here is the updated code, fix the issue which you are facing, attaching screenshot for reference.. just replace this code and run :)

cell?.buttonAction = { [self] sender in
                
                if selectedRows.contains(arrayModel[indexPath.row].id) {
                    if let indexToRemove = selectedRows.firstIndex(of: arrayModel[indexPath.row].id) {
                        
                        let name = arrayModel[indexPath.row].name
                        if selectedNamesArray.contains(name) {
                            
                            if let indexofName = selectedNamesArray.firstIndex(of: name) {
                                selectedNamesArray.remove(at: indexofName)
                            }
                        }
                        
                        selectedRows.remove(at: indexToRemove)
                        cell?.isChecked = false
                    }
                } else {
                    selectedRows.append(arrayModel[indexPath.row].id)
                    selectedNamesArray.append(arrayModel[indexPath.row].name) // Add the corresponding name
                    cell?.isChecked = true
                }
                print("Selected rows: \(selectedRows)")
                print("Selected names: \(selectedNamesArray)")
            }

enter image description here

Thanks

enter image description here

enter image description here

enter image description here