Search code examples
swiftnstableviewcocoa-bindingsnsarraycontroller

NSTableView showing last object in every row


I'm banging my head against the wall trying to figure this out. I have a very simple app with a class Person, an NSTableView and an NSArrayController "PersonController".

Person:

class Person: NSObject {
    var firstName = ""
    var lastName = ""
}

PersonController:

  • Added outlet to ViewController
  • Attributes Inspector > Object Controller > Class Name = Person

TableView:

  • Attributes Inspector > Table View > Content Mode = Cell based
  • 1st Table Column bound to Person Controller with Controller Key: arrangedObjects and Model key path: firstName
  • 2nd Table Column bound to Person Controller with Controller Key: arrangedObjects and Model key path: lastName

ViewController:

class ViewController: NSViewController {
    @IBOutlet var personController: NSArrayController!
    override func viewDidLoad() {
        super.viewDidLoad()
        let person = Person()
        var people = [Person]()
        person.firstName = "John"
        person.lastName = "Snow"
        people.append(person)
        person.firstName = "Kate"
        person.lastName = "Dawson"
        people.append(person)
        person.firstName = "Tom"
        person.lastName = "Anderson"
        people.append(person)
        personController.addObjects(people)
    }
    override var representedObject: AnyObject? {
        didSet {}
    }
}

Output:

enter image description here

What am I doing wrong here? I've read many SO posts and a ton of tutorials etc and from what I can tell I'm doing it correctly but I can't for the life of me get this to work.


Solution

  • You only have one Person object. When you append it to the array, that doesn't make a copy. The array just contains a reference to that one object. You're appending the same object three times, so the array contains three references to that one object.

    Each time you change that one Person's firstName and lastName, you're changing that one object's properties. So, at each index of the array, the table finds that one object with the last values set for its name properties.

    You need to create three separate Person objects.

    As a separate matter, you need to mark the properties of Person as dynamic if you want them to be Key-Value-Observing-compliant and thus Bindings-compatible.