[swift-users] Issues with UITableView*

Adam Stoller ghoti1 at gmail.com
Mon Sep 12 17:43:30 CDT 2016


I will respond to this directly to Ole - as I was informed this was not the correct list for such discussions, and I have since unsubscribed and subscribed to the cocoa-dev list instead.  Many thanks…


—fish
(Adam Stoller)

> On Sep 12, 2016, at 18:41, Ole Begemann <ole at oleb.net> wrote:
> 
> > Hmm - interesting to know.  Unfortunately, if I do that, then I get
> > NO indication of selection when I click on ANY row.  Perhaps I need
> > to make some other changes to account for the change in how I get the
> > cell?
> 
> You also need to store your cells' selection state someplace outside of the cells themselves. The cells should not be the "source of truth" for the selection state. Otherwise, when you scroll a cell off screen and then scroll it back, it will lose its state.
> 
> So you should store the selection state of each table row somewhere alongside your `locationList` array. Maybe as an array of pairs like this:
> 
>    var locationList: [(location: LocationObject, selected: Bool)] = [
>        (
>            location: LocationObject(name: "name-1", address: "addr-1", phone: "phone-1", latitude: 40.0, longitude: -80.1),
>            selected: false
>        ),
>        (
>            location: LocationObject(name: "name-2", address: "addr-2", phone: "phone-2", latitude: 40.0, longitude: -80.1),
>            selected: false
>        )
>    ]
> 
> There may be better ways to structure your model data, but this should suffice for now.
> 
> Then:
> 
> 1. In `tableView(_:cellForRowAtIndexPath:)`, use the current value of `item.selected` to configure the cell's selection state:
> 
>    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
>        let cell = tableView.dequeueReusableCellWithIdentifier("resultCell", forIndexPath: indexPath) as! ExistingLocationTableViewCell
>        let item = locationList[indexPath.row]
> 
>        cell.nameLabel.text     = item.location.name
>        cell.locationLabel.text = item.location.address
> 
>        cell.accessoryType = item.selected ? .Checkmark : .None
> 
>        return cell
>    }
> 
> One note: on iOS, the convention for table views is that rows should generally not remain selected after the user lifts their finger. Adding the checkmark should be enough to show a cell's selection state. I would only set the checkmark and leave `cell.selected` as is (I left it out in the code above).
> 
> 2. In `didSelectRow...`, toggle the selection state in your model data:
> 
>    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
> 
>        // Update model
>        let row = indexPath.row
>        locationList[row].selected = !locationList[row].selected
> 
> To update the UI, you now have two choices. Either ask the table view for the cell at the index path and modify the cell directly:
> 
>        // Either do this:
>        if let cell = tableView.cellForRowAtIndexPath(indexPath) {
>            cell.accessoryType = locationList[row].selected ? .Checkmark : .None
>        }
> 
> If you do that, I don't think you need to reload the cell explicitly. Alternatively, tell the table view to reload the cell as you are doing now. It will then call `tableView(_:cellForRowAtIndexPath:)` again, which in turn will configure the cell with your model data:
> 
>        // Or this:
>        tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
> 
> Finally, fade out the cell selection:
> 
>        tableView.deselectRowAtIndexPath(indexPath, animated: true)
>    }
> 
> 3. If you are okay with keeping the cells deselected unless the user's finger is onscreen, you don't need to implement `didDeselectRow...` at all.
> 
> (I typed this mostly without help from the compiler as I don't have a Swift 2.x handy, so there may be some errors in the code above.)
> 
> Ole



More information about the swift-users mailing list