NSTableView dataSource soll nicht der AppDelegate sein

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • NSTableView dataSource soll nicht der AppDelegate sein

    Hallo,

    irgendwie habe ich mich verrannt. Bin schon länger iOS Entwickler und wollte jetzt auch mal eine Mac-App probieren. Also CocoaTouch behaupte ich verstanden zu haben, Cocoa ist mir neu.

    Ich möchte gerne, dass die dataSource zum NSTableView ein NSWindowController ist, den ich anlege, und nicht der AppDelegate. Ich bekomme aber immer folgendes in die Konsole gedonnert:

    Quellcode

    1. *** Illegal NSTableView data source (<NSApplication: 0x1006087b0>). Must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:


    Warum NSApplication? Der File's Owner des nib ist auf meine Window Controller Klasse gesetzt und die dataSource des NSTableView im Interface Builder zeigt auf File's Owner. Und meine WindowController Klasse implementiert die Methoden natürlich auch ordentlich.

    Ich hab das schon mit dem MainMenu.xib probiert, das beim Projekt erstellen automatisch angelegt wird und mit einem neuen xib, dass ich dann in der Info.plist als "Start-xib" eingetragen habe.

    In beiden fällen ist das Outlet in meinem Window Controller, dass ich dort für die TableView angelegt habe auch ordentlich verknüpft und nicht nil.

    Nur das mit der dataSource haut einfach nicht hin! Verflixt! Warum will der immer NSApplication als dataSource nehmen und nicht meinen WindowController?

    Wenn ich die dataSource auf den AppDelegate lege, dann funktioniert auch alles wie erwartet. Nur ich kann doch nicht alles in den AppDelegate stecken, das ist doch bäh!

    Ich fürchte, ich hab noch irgendein konzeptuelles Problem. Kann mir mal einer auf die Sprünge helfen? Danke schonmal!
  • Danke, aber das ist nicht das Problem. Der WindowController hat die Methoden schon implementiert (wie ich oben schon schrieb).

    Das Problem ist, dass irgendwer der Meinung ist, dass ein NSApplication Objekt der dataSource delegate wäre und ich nicht weiß, was ich im InterfaceBuilder falsch mache. Ich möchte bitte, dass meine WindowController Klasse der dataSource delegate ist. Wie mache ich das?
  • Einen TableViewDelegate habe ich gar nicht verbunden.

    Ich brauche nur den TableViewDataSourceDelegate und der zeigt im IB auf File's Owner. Und wenn ich dann links den File's Owner auswähle dann steht meine WindowController Klasse im Inspector auch drin.

    Aus meiner (offenbar falschen) Sicht sieht im IB alles korrekt aus. Trotzdem wird zur Laufzeit auf das NSApplication Objekt zugegriffen. :(

    Danke euch!
  • Dann würde ich mal sagen ist die Instanz deine ViewControllers nicht die Instanz die der IB erwartet. Es nutzt ja nichts wenn du dem Files Owner nur sagst er soll von der Klasse ViewController sein, er muss auch die richtige Instanz verwenden

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • smk schrieb:

    Einen TableViewDelegate habe ich gar nicht verbunden.

    Ich brauche nur den TableViewDataSourceDelegate und der zeigt im IB auf File's Owner. Und wenn ich dann links den File's Owner auswähle dann steht meine WindowController Klasse im Inspector auch drin.

    Aus meiner (offenbar falschen) Sicht sieht im IB alles korrekt aus. Trotzdem wird zur Laufzeit auf das NSApplication Objekt zugegriffen. :(

    Danke euch!

    FileOwner ist ein Objekt, das beim Laden der NIB angegeben wird, nicht unbedingt eines der Klasse die IB anzeigt, denn der kennt Deinen Code nicht. Er muss aber wissen welche Klasse das sein sollte (!), damit die richtigen Outlets angezeigt werden.
    Normalerweise (d.h. wenn Du die NIB nicht von Hand lädst) ist das ein AppController, also Delegate der NSApp.

    Lädst Du die NIB wirklich über deinen WindowController?

    Das Ganze ist ein bischen undurchsichtig, aber bei Document-Based-Applications sehr mächtig und auch notwendig, damit jedes Dokument einen eigenen WindowController, ein eigenes Document und eben auch einen eigenen TableViewDelegate hat. Und wenn man dann noch Fenster haben will, die für die ganze Application gelten (z.B. Auswahl aller Benutzten oder Offenen Dokumente), dann gibt es TableViewDelegates sowohl zu den Dokumenten, als auch zum AppDelegate.
  • Hmm. Ich fürchte dann geht es jetzt an Eingemachte. So richtig 100% habe ich das Laden der NIBs wohl nicht verstanden.

    Das XIB ist ja in der Info.plist eingetragen. Also wird es automatisch geladen. Ich dachte immer, dass dann automatisch der Controller dazu angelegt wird. Und zwar als Instanz der Klasse, die ich bei File's Owner im Identity Inspector angegeben habe.

    Oder nicht?

    :rolleyes:

    Also um nochmal auf die Frage zu antworten: Nein, ich lade die NIB nicht über den WindowController. Ich möchte dass die initial geladene NIB aus der Info.plist einen WindowController als Besitzer hat. Das soll nicht der AppDelegate sein. Oder ist das unüblich?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von smk ()

  • Ich dachte das passiert automatisch, weil ich das doch im Interface Builder so eingetragen habe und es eben gerade das erste NIB ist, das was in der Info.plist als NSMainNibFile eingetragen ist. Erwarte ich da zuviel?

    Aber ist ja auch wurscht. Offensichtlich bin ich auf dem Holzweg. Aber wie macht man es denn dann richtig?

    Ist bei einer Single-Window Applikation dann immer der AppDelegate der File's Owner des initialen NIBs?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von smk ()

  • Also perse kann man sagen, dass die alle erstmal nichts mit einer TableViewDataSource zu tun haben.

    Was ich nicht so ganz bei dir verstehe: Warum instanztierst du nicht deinen NSWindowController im IB, verlinkst ihn mit der TableView und gibts dem NSWindowController in der Klassenbeschreibung die entsprechenden Methoden für die NSTableViewDataSource mit?
    [self setSignature:null];
    [[self postCount] increment];
  • smk schrieb:

    Ich dachte das passiert automatisch, weil ich das doch im Interface Builder so eingetragen habe und es eben gerade das erste NIB ist, das was in der Info.plist als NSMainNibFile eingetragen ist. Erwarte ich da zuviel?

    Zumindest erwartest Du das Falsche. Der File's Owner ist nur ein Platzhalter Objekt, damit Du im Interface Builder Verknüpfungen „nach außen“ machen kannst. Welches reale Objekt aber letztendlich den Platz des File's Owners zur Laufzeit einnimmt wird, wie uns in Post #10 bereits sagte, erst beim Laden des Nib Files festgelegt. Das Funktioniert in iOS übrigens exakt genau so.

    smk schrieb:

    Aber ist ja auch wurscht. Offensichtlich bin ich auf dem Holzweg. Aber wie macht man es denn dann richtig?

    Du kannst einfach Dein Datasource Objekt in dem Main Nib File instanzieren.

    smk schrieb:

    Ist bei einer Single-Window Applikation dann immer der AppDelegate der File's Owner des initialen NIBs?

    Nein, ist es nicht. Schau Dir die Fehlermeldung noch mal genau an.
    Der File's Owner vom Main Nib File ist üblicherweise NSApplication. Das AppDelegate Objekt ist halt das Delegate Objekt von NSApplication, welches im Main Nib File instanziert ist. Die Klasse des File's Owners im Main Nib File wird in der Info.plist festgelegt (Key: NSPrincipalClass).

    Michael
  • @mike: Wie genau "instanziiere ich denn meinen WindowController in meinem NIB"? Den Rest habe ich ja genau so gemacht. Methoden implementiert und mit dem TableView verlinkt. Nur wie "instanziiert" man im IB?

    @Michael: gleiche Frage: wie genau "instanziiere ich mein Datasource Objekt in dem Main Nib File"?

    Vielleicht weiß ich ja schon, was ihr meint und kenne es nur unter dem Begriff "instanziieren im NIB" nicht?


    Das mit NSPrincipalClass war mir gar nicht mehr bewusst, musste ich wohl noch nie ändern. Aber das kann ich ja nicht auf meinen WindowController legen. Der ist ja kein NSApplication Delegate, also kracht es gleich mal mit einem "unrecognized selector". Was mich dann wieder zu meiner Frage von vor zwei Posts bringt (diesmal mit mehr Hintergrundwissen):

    Ist es bei SingleView Applikationen auf dem Mac üblich, dass es keinen eigenen WindowController für das eine Hauptfenster gibt, sondern das automatisch der AppDelegate mit abwickelt?

    Unter iOS gibt es ja (unter normalen Umständen) immer nur das eine Window und das bekommt dann im AppDelegate mit self.window.rootViewController das erste NIB. Damit ist dann aber der AppDelegate von der RootViewController Klasse schön getrennt. So etwas wollte ich mit der Mac App dann auch gerne haben.

    Zur weiteren Modularisierung habe ich auf dem Mac neben den WindowControllern ja auch noch ViewController, die muss ich mir aber erstmal angucken. Vielleicht ist das ja das Instrument, dass ich suche? Ich hab ja auch nur ein Window. Ich will es nur gleich am Anfang richtig machen. Das eine Fenster soll mit Splittern schon einen Haufen gut trennbare Funktionalität erhalten und das alles in die eine AppDelegate Klasse zu packen, fühlt sich irgendwie falsch an.

    Danke Kollegen!
  • smk schrieb:

    @Michael: gleiche Frage: wie genau "instanziiere ich mein Datasource Objekt in dem Main Nib File"?

    Genauso, wie in iOS Projekten. Aus der Objekt Library ein Objekt in den Objects Bereich des xib-Editors ziehen und diesem Objekt dann Deine Datasource Klasse zuweisen.

    smk schrieb:

    Das mit NSPrincipalClass war mir gar nicht mehr bewusst, musste ich wohl noch nie ändern.

    Musste ich auch noch nie.

    smk schrieb:

    Ist es bei SingleView Applikationen auf dem Mac üblich, dass es keinen eigenen WindowController für das eine Hauptfenster gibt, sondern das automatisch der AppDelegate mit abwickelt?

    Nein, das AppDelegate macht da gar nichts. Die Funktion NSApplicationMain() erzeugt die NSApplication Instanz, lädt das Main Nib File und startet dann die Application. Diese Funktion wird in der main Funktion aufgerufen. Unter iOS ist es das gleiche Prinzip.

    smk schrieb:

    Unter iOS gibt es ja (unter normalen Umständen) immer nur das eine Window und das bekommt dann im AppDelegate mit self.window.rootViewController das erste NIB. Damit ist dann aber der AppDelegate von der RootViewController Klasse schön getrennt. So etwas wollte ich mit der Mac App dann auch gerne haben.

    Wie schon gesagt, kannst Du Dir eine eigene „Controller Klasse“ machen und die direkt im Main Nib File instanzieren. Wenn Du es richtig getrennt haben willst, kannst Du auch das Fenster aus dem Main Nib löschen und in ein eigenes xib auslagern. Das lädst Du dann mit einem NSWindowController.

    smk schrieb:

    Zur weiteren Modularisierung habe ich auf dem Mac neben den WindowControllern ja auch noch ViewController, die muss ich mir aber erstmal angucken. Vielleicht ist das ja das Instrument, dass ich suche? Ich hab ja auch nur ein Window. Ich will es nur gleich am Anfang richtig machen. Das eine Fenster soll mit Splittern schon einen Haufen gut trennbare Funktionalität erhalten und das alles in die eine AppDelegate Klasse zu packen, fühlt sich irgendwie falsch an.

    Window und ViewController sind vor allem dazu gedacht, Fenster bzw. View aus weiteren Nibs zu laden. Wenn Du alles in einem Nib hast, reicht eine Subklasse von NSObjekt als „Controller Klasse“ völlig aus.

    Falls es Dir noch an Lesestoff mangelt, hier ist noch was. ;)

    Michael
  • Michael schrieb:

    smk schrieb:

    @Michael: gleiche Frage: wie genau "instanziiere ich mein Datasource Objekt in dem Main Nib File"?

    Genauso, wie in iOS Projekten. Aus der Objekt Library ein Objekt in den Objects Bereich des xib-Editors ziehen und diesem Objekt dann Deine Datasource Klasse zuweisen.

    Ähm. Ich kann doch aus der Object Library nicht meinen Window Controller instanziieren? Der ist doch da gar nicht drin. Ich kann da einen NSTableView hernehmen und genau das habe ich ja auch gemacht. Und ich habe diesem NSTableView ja auch meinen NSWindowController als DataSource im IB zugewiesen. Trotzdem werden die Methoden meines WindowControllers zur Laufzeit nicht aufgerufen.

    Michael schrieb:

    smk schrieb:

    Ist es bei SingleView Applikationen auf dem Mac üblich, dass es keinen eigenen WindowController für das eine Hauptfenster gibt, sondern das automatisch der AppDelegate mit abwickelt?

    Nein, das AppDelegate macht da gar nichts. Die Funktion NSApplicationMain() erzeugt die NSApplication Instanz, lädt das Main Nib File und startet dann die Application. Diese Funktion wird in der main Funktion aufgerufen. Unter iOS ist es das gleiche Prinzip.

    Mit dem zweiten, dritten und vierten Satz bin ich einverstanden. Aber was haben die mit dem ersten zu tun? Natürlich lädt der AppDelegate unter iOS den RootViewController, der macht nicht "nichts". Und wenn ich mir so die Beispiele für Anfänger angucke, dann soll man im IB den DataSourceDelegate das NSTableView auf den AppDelegate setzen. Und dann macht der auch nicht "nichts", sondern alles. Der AppDelegate ist dann gerade die DataSource des NSTableView.

    Michael schrieb:

    Wie schon gesagt, kannst Du Dir eine eigene „Controller Klasse“ machen und die direkt im Main Nib File instanzieren.

    Genau diesen Satz kann ich nicht umsetzen. Kannst Du das bitte noch etwas genauer erklären? Meine NSWindowController Klasse taucht in der Object Library doch gar nicht auf!

    Michael schrieb:

    Wenn Du es richtig getrennt haben willst, kannst Du auch das Fenster aus dem Main Nib löschen und in ein eigenes xib auslagern. Das lädst Du dann mit einem NSWindowController.

    Ah. Das Hauptfenster aus dem Main Nib löschen geht? Das muss ich mal probieren. Unter iOS hatte ich ja immer nur mit Views zu tun, nie mit Fenstern. Das kann ich dann ganz normal im Code des AppDelegate laden, in dem ich dort meinen NSWindowController mit initWindowWithNibName: lade. Das klingt sehr gut!

    Michael schrieb:

    Wenn Du alles in einem Nib hast, reicht eine Subklasse von NSObjekt als „Controller Klasse“ völlig aus.

    Naja, das ist ja dann offensichtlich irgendwie der Knackpunkt. Natürlich hatte ich bisher alles in einer NIB, wollte aber verschiedene "Controller Klassen" für dieses eine NIB, nämlich eine eigene für das NSWindow da drin.

    Michael schrieb:

    Falls es Dir noch an Lesestoff mangelt, ...

    Äh, Danke. Da war ich natürlich schon. Mir scheint, etwas fundierteres Hintergrundwissen zu NIBs täte mir ganz gut. Trotzdem vielen Dank für die Erklärungen! :rolleyes: