Bindings am Beispiel von NSTableView

  • Bindings am Beispiel von NSTableView

    Hallo,

    die “Bindingstechnologie” ist für viele (für mich eingeschlossen) noch ein etwas magisch wirkendes Gebilde. Leute wie Tom sorgen mit all ihrer Kraft für Aufklärung auf diesem Gebiet - erklären immer wieder, dass Bindings eigentlich nur KVC/KVO in Komibination sind. Dennoch bleibt - zumindest bei mir - immer ein Rest, der ungeklärt bleibt. Es wäre wohl ganz sinnvoll Bindings mal ein einem komplexen aber konkreten Beispiel wie NSTableView zu erklären.

    Die Frage ist: Wie kommen die Daten (via Bindings) in die TableView, wie werden die Änderungen “bekannt” gegeben, wie die SelectionIndexes gemanaged usw. Diese Fragen habe ich mir vor Kurzem wieder gestellt, da ich ein TableView ähnliches CustomView schreibe.

    Hier mein Ansatz:

    NSTableView kennt den NSArrayController, der die Daten bereitstellt. Dies wird mittels des Content-Bindings von NSTableView sichergestellt.
    Apple Doku über das content-Binding von NSTableView:
    “An NSArrayController instance that provides the content of the NSTableView.
    Typically, the content binding is created automatically when the initial NSTableColumn binding is made, binding to the column's NSArrayController.”
    Wunderbar. Somit kennt NSTableView durch [[self content] arrangedObjects] auch die schon sortierten Daten, die es bereitstellen muss.

    Ein NSTableView hat meist mehrere Spalten. Was nun in welche Spalte soll wird der entsprechenden Spalte über deren value-Binding mitgeteilt. Mit dem keyPath des value Bindings wird einfach der ArrayController der Table befragt.

    Soweit richtig?

    Dann gehts weiter:
    An einer Stelle im Code rufe ich die add: Methode des ArrayControllers auf. Wie durch Zauberhand erscheint in der TableView ein neuer Eintrag. Wie das? Die TableView wird kaum alle paar Sekundenbruchteile sich selbst komplett neu laden...

    Wie sieht es mit Änderungen aus, die ich vom Code aus an einen Objekt welches im ArrayController ist vornehme. Diese Änderung wird vom TableView auch sofort angezeigt. Tom hat in Wiki erklärt, dass und wie man ein Array observieren kann. Observiert die Table also tatsächlich [[self content] arrangedObjects] auf Änderungen und reagiert darauf einfach mit einem [self setNeedsDisplay:YES]?

    Weiter zu den SelectionIndexes:
    Klicke ich wie wild in der TableView rum ermittelt die TableView wohl anhand meiner Rumklickerei ihre neuen SelectionIndexes und übergibt diese an ihren ArrayConroller. Oder?
    Die Objective-Cloud ist fertig wenn sie fertig ist. Beta heißt Beta.

    Objective-C und Cocoa Band 2: Fortgeschrittene
    Cocoa/Objective-C Seminare von [co coa:ding].
  • RE: Bindings am Beispiel von NSTableView

    So in etwa, vielleicht mal etwas mehr ins Detail. Der Teil "Under Cosntruction" auf der Seite muss dringend ausgebaut werden. Dafür aber BTW auch eine gute Nachricht: In Absolute Beginners sind die Teile 6 & 7 fertig. Aber zurück zum Thema.

    1. Wie funktioniert die Geisterhand
    Sie funktioniert über KVO, was keine anständiige Antwort ist, weil sich die Frage stellt wie KVO funktioniert. Um es kurz zu machen: Wenn ich auf ein Objekt eine Observierung ändere, baut Cocoa zur Laufzeit eine neue Klasse. Diese seiht der originalen zum Verwechseln ähnlich, führt auch deren Methoden aus, jedoch mit einem kleinen Unterschied: Bei den Setter und Getter der observierten Eigenschaft wird Code eingeschmuggelt, der die Observierung behandelt, also den Callback observeValue:forObject... aufruft.
    Ganz kurz gibt es das hier:
    "Key-Value Observing Implementation Details

    Automatic key-value observing is implemented using a technique called isa-swizzling.

    The isa pointer, as the name suggests, points to the object's class which maintains a dispatch table. This dispatch table essentially contains pointers to the methods the class implements, among other data.

    When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance.

    Instead of relying on the isa pointer your application should use the class method to determine the class of an object instance."

    2. To-Many-Bindings
    Ja, du musst die To-Many-Relationship wie auch die dich interessierenden Attribute der enthaltenen Objekte observieren. Ich mache das gerade in einem dreistöckigen (n-stöckigem) System, welches allerdings noch Probleme aufwirft. (Es geht um rekursive Observierung von Prädikaten. Du kannst sozusagen Prädikate rekursiv verschachteln und dies auf ein Array anwenden.)

    Bei Änderungen des Arrays musst du deshalb aufpasen, dass du die enthaltenen Objekte wieder unobservierst. (Das beschreibe ich ja auch.) Umgekehrt müüssen die neuen Objekte observiert werden. Ein einfaches Neuzeichnen reicht also nciht.

    Ein Beispiel
    Tabelle mit Namen und Vornamen, Array mit drei Objekten:

    Quellcode

    1. Negm-Awad | Amin
    2. Objcler | Egon
    3. Müller | Fritz
    Jetzt existieren iinsgesamt 7 Obserrvierungen
    1. Die Observierung des Arrays (also der Beziehung in der Mutterentität, die die Beziehung hält, etwa Employees in Company.)
    2. Das Attribut Nachname der ersten Instanz (Negm-Awad)
    3. Das Attribut Vorname der ersten Instanz (Amin)
    4. Das Attribut Nachname der zweiten Instanz (Objcler)
    ...
    ...
    7. Das Attribut Vorname der dritten Instanz (Fritz)

    Schlägt eine der Observierungen 2 bis 7 ein, so reicht ein einfaches Neuzeichnen.
    Schlägt aber die Observierung 1 ein, so müssen die Observierungen der nunmehr fehlenden Objekte gelöscht und die Observierungen der neu hinzugekommenen Objekte eingerichtet werden.

    Wozu brauchst du das eigentlich?
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Danke erstmal. Werde das morgen mal Zeile für Zeile durchgehen.

    Ich habe für mein Vokabeltrainer ein NSTableView, welche für Vorder und Rückseite je eine Spalte hat. Nun möchte ich ein weiteres View "anbieten", welches den Inhalt des TableViews auf eine andere Art und Weise präsentiert.
    Die Objective-Cloud ist fertig wenn sie fertig ist. Beta heißt Beta.

    Objective-C und Cocoa Band 2: Fortgeschrittene
    Cocoa/Objective-C Seminare von [co coa:ding].
  • Na supi. Ich habe aber heute bis gerade beim Gericht und einer Durchsuchung gehangen, weil letzte Nacht ein Mandant von mir verhaftet wurde. Also dazu habe ich jetzt echt keinen Bock mehr. :)

    Aber ich schaue es mir an.

    BTW: Kommstt du zum Treffen?
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von Tom9811
    Na supi. Ich habe aber heute bis gerade beim Gericht und einer Durchsuchung gehangen, weil letzte Nacht ein Mandant von mir verhaftet wurde. Also dazu habe ich jetzt echt keinen Bock mehr. :)

    Aber ich schaue es mir an.

    BTW: Kommstt du zum Treffen?


    Das Beispiel ist wirklich simpel. Mittlerweile bin ich mit meinem eigenen view so weit, dass er die observer auch wieder schön "removed".

    Ich komme nicht zum Treffen. Jedenfalls ist es nicht geplant.
    Die Objective-Cloud ist fertig wenn sie fertig ist. Beta heißt Beta.

    Objective-C und Cocoa Band 2: Fortgeschrittene
    Cocoa/Objective-C Seminare von [co coa:ding].
  • Welchen Artikel meinst du? Deinen Beitrag hier in diesem Thread?

    Ja - in so weit, dass ich nun weiß, dass der Gedanke den ich hatte (mein NSView Subclass bei jedem interessanten Objekt als Observer zu melden) richtig war. Mein View kann nun auf Änderungen, die eine andere Stelle an den observierten Objekten vornimmt reagieren. Allerdings reagiert mein View noch nicht auf das Erzeugen neuer Objekte.

    Falls du das in deinem Post schon beantwortet hast, dann bin ich zu doof :)

    Aber du schreibst ja in dem Wikiartikel:

    "Werden dort aber Objekte hinzugefügt oder entfernt, so müssen die Observationen dier hinzugefügten oder entfernten Objekte an- bzw. abgemeldet werden."

    Mit "dort" meinst du ja ein Array...

    Genau das ist ja mein Problem. Die add: Action von NSArrayController wird getriggert. Ein neues Objekt wird erzeugt. Mein konkretes Problem: wie erfährt mein View davon? @count kann ich ja nicht observieren...

    Was ist ein "OP"?
    Die Objective-Cloud ist fertig wenn sie fertig ist. Beta heißt Beta.

    Objective-C und Cocoa Band 2: Fortgeschrittene
    Cocoa/Objective-C Seminare von [co coa:ding].
  • Nee, ich meinte meinen Wiki-Artikel.

    Also, du hast natürlich recht, dass man auch @count nicht observieren kann. (Die @Schlüssel gehören ohnehin in die Tonne getreten.) Aber das Array hängt ja irgendwo an einer Entität. Und das Attribut der Entität kannst du observieren. Beispiel von oben:

    Du hast Company:
    NSString* name;
    NSString* address; // die beiden nur, um irgendwas zu haben, Veranschaulichung.
    NSArray* employees; // DAS ist interessant

    Employees verweist jetzt auf deine einzelnen Objekte, die in der Beziehung liegen. Du kannst aber die Eigenschaft employees von einer (der?) Company-Instanz observieren. Und wenn du das machst, dann bekommst du Hinzufügungen und Entfernungen über KVO mit.

    Quellcode

    1. [theCompany addObserver:self forKeyPath:@"employees" …


    Hmm, IIRC gibt es dazu in Graphic Bindings ein Example. Ich weiß nicht merh, wie es genau heißt.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Das nehme ich als Kompliment. :)

    Da gab es auch ein paar bemerkenswerte Kommentare zu KVO, IIRC. Sind die noch da?

    (Ich fand sie damals richtig. Inzwischen habe ich bemerkt, dass Cocoa/Apple Recht haben.)
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Darf ich mal fragen, von welchem Wiki-Artikel hier die Rede ist? Ich versuche nämlich gerade das Kapitel Model-View-Controller und Bindings aus dem Buch »Objective-C und Cocoa« auf mein NSTableView-Problem anzuwenden und bräuchte noch etwas mehr Theorie.

    Marco
  • Vielen Dank für die schnelle Antwort. Aber den Artikel über Bindings finde ich von der Formatierung her eher fragwürdig. Da sind eine Menge Fehler hineingerutscht, die das Lesen extrem erschweren. Naja werd mich jetzt erstmal so durcharbeiten.

    Marco
  • Original von m99
    Vielen Dank für die schnelle Antwort. Aber den Artikel über Bindings finde ich von der Formatierung her eher fragwürdig. Da sind eine Menge Fehler hineingerutscht, die das Lesen extrem erschweren. Naja werd mich jetzt erstmal so durcharbeiten.

    Marco


    Als der Artikel verfasst wurde war eine andere Wikisoftware im Einsatz, welche andere Tags zur Formatierung nutzte.
    Die Objective-Cloud ist fertig wenn sie fertig ist. Beta heißt Beta.

    Objective-C und Cocoa Band 2: Fortgeschrittene
    Cocoa/Objective-C Seminare von [co coa:ding].
  • Nicht weiterkommen wäre falsch formuliert. Ich kann das gelernte zu den Bindings nicht so richtig auf meine Problemstellung anwenden. Ich habe ein NSTableView, das ja mit Daten gespeist wird. Nun würde ich mein Programm gern auf Bindings umstellen und so die Sortierung der Spalten ermöglichen. Denn bisher scheitert dies daran, daß ich die Werte in der entsprechenden Funktion mehr oder weniger ungewollt immer in der gleichen Reihenfolge ausgebe. Also allgemein hätte ich es besser gefunden, wenn man die Bindings an einem NSTableView-Problem erklärt hätte. Im ersten Teil des Kapitels MVC sind außerdem - wie auch im gesamten Buch - Fehler, die das MVC-Paradigma aushebeln. Aber die sind in der Errata bestimmt schon korrigiert.

    Marco