Tolgay Toklar
Tolgay Toklar

Reputation: 4343

Selecting multiple objects at tableview

I am using table view for selecting objects. I want to select muliple objects in a tableview. I am using following code:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell: ContactCell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier) as! ContactCell

    let row = indexPath.row
    let person=contacts[row]
    cell.setCell(person.nameLabel,image: "")
    return cell
}


func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    let row = indexPath.row
    let person=contacts[row]

    if let cell = tableView.cellForRowAtIndexPath(indexPath) {
        if cell.accessoryType == .Checkmark
        {
            cell.accessoryType = .None
        }
        else
        {
            cell.accessoryType = .Checkmark
        }
    }
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

My tableview looks like this:

enter image description here

I selected the "Kate" then I scroll down to bottom and "Test" is marked too. But why? I selected just "Kate". How can I prevent this?

Upvotes: 0

Views: 610

Answers (2)

Dennis Weidmann
Dennis Weidmann

Reputation: 1967

It is selected "too", because inside a UITableView cells are reused...

let cell: ContactCell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier) as! ContactCell

If you want to solve this problem, the best way would be to save each cells state inside the array, which is holding your data of the UITableView... This is the best way.

Another way would be to declare a Dictionary of type [Int: Bool] and save your selected states to this... the Int key would be the row index, and its value could be true for selected, or false for not...

UPDATE

Following an example on how to solve your problem

class CustomTableViewController: UITableViewController {

    @IBOutlet weak var contactsTableView: UITableView!
    lazy var contactsArray: [[String: AnyObject]] = [[String: AnyObject]]()

    //This method is to convert your contacts string array, into the array you need
    private func appendContactsToContactsArray (contacts: [String]) {
        for contact in contacts {
            contactsArray.append(["name": contact, "selected": false])
        }
        contactsTableView.reloadData()
    }

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

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

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell: ContactCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! ContactCell

        cell.textLabel?.text = contactsArray[indexPath.row]["name"] as? String

        if (isCellSelectedAtIndexPath(indexPath)) {
            cell.accessoryType = UITableViewCellAccessoryType.Checkmark
        } else {
            cell.accessoryType = UITableViewCellAccessoryType.None
        }

        return cell
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        if (isCellSelectedAtIndexPath(indexPath)) {
            contactsArray[indexPath.row]["selected"] = false
        } else {
            contactsArray[indexPath.row]["selected"] = true
        }
        tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
    }

    private func isCellSelectedAtIndexPath (indexPath: NSIndexPath) -> Bool {
        return contactsArray[indexPath.row]["selected"] as? Bool ?? false
    }

}

Upvotes: 1

Phillip Mills
Phillip Mills

Reputation: 31016

You're seeing this effect because cells are cached and reused. Note the word "Reusable" in dequeueReusableCellWithIdentifier.

Make "selected" a property of a contact or person. Set it true or false when a row is selected or deselected. Reload your data and set the accessory type in cellForRowAtIndexPath.

Upvotes: 0

Related Questions