Verständnisfrage: Zusammenspiel NotificationCenter und Sheets

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

  • Verständnisfrage: Zusammenspiel NotificationCenter und Sheets

    Hallo allerseits,

    nach längerer Zeit Cocoa-Abstinenz habe ich vor ein paar Tagen mit der Implementierung eines Aperture-Export-Plugins begonnen. Langsam nimmt es Formen an, ich stosse aber immer wieder auf Probleme, die mich unnötig Zeit kosten. Das letzte habe ich heute morgen gelöst, ich verstehe jedoch nicht warum - vielleicht kann mich ja jemand erleuchten ;)

    Ausgangslage: Beim Start des Plugins wird überprüft, ob bereits die benötigten Einstellungen gespeichert sind, und falls nicht, wird ein Sheet eingeblendet, auf dem der Benutzer die Einstellungen machen kann. Dazu wird mein Controller als Observer von NSWindowDidBecomeKeyNotification registriert, da zum Zeitpunkt von awakeFromNib das Export-Fenster noch nicht Key ist. Bei einer Notification wird dann folgende Methode ausgeführt (ungefähr, ich habe den Code gerade nicht vor mir):

    Quellcode

    1. - (void)checkSettings:(NSNotification *)notification {
    2. if(preferences == nil) {
    3. [NSApp beginSheet:settingsWindow modalForWindow:[exportManager window] modalDelegate:nil didEndSelector:nil contextInfo:nil];
    4. } NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
    5. [defaultCenter removeObserver:self];
    6. }



    Die Folge ist allerdings, dass nachdem das settingsWindow wieder geschlossen wurde, kein weiteres Sheet mehr eingeblendet werden kann. Stattdessen kommt nur eine "visual bell".

    Wenn ich allerdings die Reihenfolge ändere:


    Quellcode

    1. - (void)checkSettings:(NSNotification *)notification {
    2. NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
    3. [defaultCenter removeObserver:self];
    4. if(preferences == nil) {
    5. [NSApp beginSheet:settingsWindow modalForWindow:[exportManager window] modalDelegate:nil didEndSelector:nil contextInfo:nil];
    6. }
    7. }



    ...dann funktioniert alles tadellos. Kann mir jemand dafür eine Erklärung geben?

    Danke & Gruss
    Daniel
    There will always be skeptics.
    There will always be disbelievers.
    And there will always be Apple to prove them wrong.
  • Hallo,

    entleere Deine -checkSettings: und lasse Dir mal Deine Nachricht ausgeben.
    Wie oft bekommst Du die Ausgabe?

    Das Problem wird sein, dass Du nicht prüfst, ob schon ein Sheet an dem Fenster klebt.
    Wenn die Methode das zwei Mal usw. aufgerufen wird, dann kollidiert das wohlmöglich.

    Du müsstest so etwas machen:

    Quellcode

    1. if([someWindow attachedSheet])
    2. {
    3. // schon da
    4. }
    5. else
    6. {
    7. // okay, kann gezeigt werden
    8. }
    Alles anzeigen


    Bei Deinem zweiten Code-Ausschnitt entfernst Du vorher den Beobachter und vermeidest somit, dass Deine Methode mehrmals aufgerufen wird und somit das Fenster kollidieren lässt.
    Das ist aber meiner Meinung suboptimal. Du solltest immer prüfen, ob schon was am Fenster hängt. Wenn Deine App wächst, dann weißt Du solche Eigenheiten in einem Jahr nicht mehr.

    Viele Grüße
  • Vielleicht noch kurz zum Informationsfluss.

    Es wird folgendes passieren:

    - Fenster A bekommt Key
    - du erhältst Deine Nachricht und öffnest das Sheet
    - das Sheet ist auch ein Fenster und das System sendet wieder eine Nachricht, dass das Fenster Key wurde
    - du erhältst Deine Nachricht und willst wieder das Sheet öffnen usw.
    - …
    - wenn Dein Sheet schließt, dann bekommt das darunter liegende Fenster A wieder Key
    - daraufhin willst Du wieder das Sheet öffnen usw.

    Im Prinzip erzeugst Du eine Schleife, da Du nicht ausreichend prüfst.

    Aber hier zeigt sich für mich, dass Dein Ansatz wohlmöglich falsch ist.
    Ich kann es nicht konkret bewerten, aber mache Dir Gedanken dazu.

    Viele Grüße
  • Ich verstehe auch nicht ganz, wieso du das über Notifications machst!?

    Dein Controller ist ein Window-Controlelr? Dann ist er Delegate des Fensters. Es gibt entsprechende Methoden dafür.

    Bei deinem Sheet kannst du ebenfalls so vorgehen.

    So ist von vorne herein klar, wer wie wo Key-Window wurde.

    Notifications sind ein ungerichteter Kommunikationskanal. Du brauchst einen gerichteten, weil du über ein bestimmtes Fenster informiert werden möchtest.
    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"?
  • @little_pixel:
    Danke, ich hatte das zwar schon etwas getestet, werde es mir aber noch einmal genauer anschauen. Ich finde es nur merkwürdig, dass man am GUI nicht sieht, dass das Sheet mehrmals eingeblendet wird. Es friert ja nicht ein, sondern verhält sich ganz normal, nur eben, dass ich danach kein weiteres Sheet aufmachen kann.

    @Amin:
    Das Aperture-Plugin implementiert selber kein eigenes Fenster, sondern nur eine NSBox, die von Aperture in ein Fenster hineingeladen wird. Der Zugriff auf dieses Fenster erfolgt über das ExportManager-Objekt. Dieses liefert aber erst dann das richtige Fenster zurück, wenn das Plugin bereits geladen wurde, also das Export-Fenster Key-Window ist. Davor bekommt man das Haupt-Fenster (was mir, glaube ich zumindest, nichts bringt).


    Weder in den initWithAPIManager- oder willBeActivated-Methoden des ApertureExportPlugin-Protokolls, noch in awakeFromNib bekomme ich das Export-Fenster (habe ich schon probiert...). Ich habe bisher keine Möglichkeit gefunden (ausser mittels Notifications), zu erfahren, wenn das Export-Fenster Key wird. Wenn es eine gibt, bin ich dafür durchaus offen :)
    There will always be skeptics.
    There will always be disbelievers.
    And there will always be Apple to prove them wrong.