12 Stimmen

Wem gehört ein NSWindowController in der gängigen Praxis?

Ich bitte um weitere Klärung, nachdem ich gesehen habe Was ist für die Freigabe von NSWindowController-Objekten zuständig?

Ich schreibe eine einfache Anwendung zur Bestandsverwaltung für meine Neffen. Ich habe eine Tabellenansicht, die den Inhalt ihrer "Bibliothek" usw. anzeigt. Um einen neuen Gegenstand zur Bibliothek hinzuzufügen, klicken sie auf eine "+"-Schaltfläche. Diese Schaltfläche öffnet ein neues Fenster, in dem sie die Details des Gegenstands eingeben können, und bestätigt die Eingabe, wenn sie auf "OK" klicken.

All das funktioniert sehr gut. Ich habe jedoch eine Frage zur Speicherverwaltung. Um das neue Fenster zu erstellen, verwende ich den folgenden Code:

- (IBAction)addNewItem:(id)sender {
  LibraryItemEditorController *editorController = 
    [[LibraryItemEditorController alloc] 
          initWithWindowNibName:@"LibraryItemEditor"];

  [editorController showWindow:nil];
  // editorController is "leaked" here, it seems.
}

Ich kann weder freigeben (noch automatisch freigeben) editorController am Ende von addNewItem: denn nichts anderes referenziert editorController Wenn ich sie loslasse, verschwindet das Fenster sofort. Ich möchte jedoch, dass der Fenster-Controller losgelassen wird, sobald das Fenster geschlossen ist. In Apples Fenster-Programmieranleitung habe ich Folgendes gelesen:

Wenn Sie möchten, dass das Schließen eines Fensters sowohl das Fenster als auch den Fenster-Controller verschwinden, wenn es nicht Teil eines Dokument ist, muss Ihre Unterklasse von NSWindowController kann beobachten NSWindowWillCloseNotification oder, da der Fensterdelegierte, implementieren Sie die windowWillClose: Methode und umfassen die folgende Codezeile in Ihre Implementierung ein:

[self autorelease];

Ich habe die [self autorelease] en el windowWillClose: Methode des Fenster-Controllers. Dies funktioniert und führt nicht zu Speicherverlusten. Allerdings fühlt es sich einfach hässlich; addNewItem: sieht aus, als ob es Speicherverluste gibt, und die statische Analyse sieht das auch so. I wissen, dass es tatsächlich in windowDidClose: aber es fühlt sich einfach falsch an. Außerdem gibt sich der Window-Controller jetzt selbst frei, ohne sich jemals selbst gehalten zu haben. Das alles verstößt gegen die Regeln der Speicherverwaltung, die ich gelernt habe.

Meine andere Option ist, ein ivar auf dem übergeordneten Controller (entweder ein NSWindowController oder ein NSMutableSet de NSWindowController s) und achten Sie dann auf die NSWindowWillCloseNotification in der übergeordneten Steuerung und geben sie als Antwort frei. Dies ist sauberer, und ist wahrscheinlich, was ich tun werde. Es ist auch eine ganze Menge mehr Arbeit, obwohl, was mich zu meinen Fragen führt.

Achtet auf die NSWindowDidCloseNotification die Standardmethode für diese Aufgabe? Was ist die Standardmethode für die Verwaltung NSWindowControllers die bei Bedarf erstellt und vernichtet werden? Ist die [self autorelease] die traditionell empfohlene Option, und erst jetzt, da wir statische Analysen haben, ist dies ein Problem?

5voto

Darren Punkte 25326

Es klingt, als ob Ihr Fenster modal ist, in diesem Fall:

[NSApp runModalForWindow:[editorController window]];
[editorController release];

Hier ist ein Muster für nicht-modale Fenster:

@implementation QLPrefWindowController

+ (id) sharedInstance
{
    if (!_sharedInstance)
    {
        _sharedInstance = [[QLPrefWindowController alloc] init];
    }
    return _sharedInstance;
}

- (void)windowWillClose:(NSNotification *)notification
{
    if ([notification object] == [self window] && self == _sharedInstance)
    {
        _sharedInstance = nil;
        [self release];
    }
}

Dann kann jeder, der auf das Fenster zugreifen oder es anzeigen möchte, dies über die +sharedInstance Klasse-Methode. Wenn das Fenster nicht bereits sichtbar ist, wird es erstellt, andernfalls erhalten sie das aktuell sichtbare Fenster.

0voto

Bryan Punkte 4070

Die oben gepostete Lösung für nicht-modale Situationen ist nicht korrekt, da Klassenmethoden nicht auf iVars zugreifen können. Ich habe dieses Problem gelöst, indem ich eine Klassenmethode (in meiner NSWindowController-Unterklasse namens LPWindowController) erstellt habe, die wie folgt aussieht:

+ (id) autoreleasingInstanceShowingWindow
{
    LPWindowController *obj = [[LPWindowController alloc] initWithWindowNibName:@"myWindow"];
    [obj showWindow:[NSApp delegate]];

    return obj; 
}

Die obige Methode gibt eine Instanz von LPWindowController mit einem Retain Count von 1 zurück und zeigt auch das Fenster des Controllers an. Das ist wichtig, denn sonst müssten wir uns darauf verlassen, dass der Aufrufer "showWindow:" aufruft, um das Fenster von LPWindowController anzuzeigen. Sollte der Aufrufer dies jemals versäumen (was wahrscheinlich ein Fehler wäre), würde der Controller nie freigegeben werden. Indem wir die Anzeige des Fensters bei der Zuweisung/Initierung des Controllers erzwingen, vermeiden wir diesen Fallstrick.

Als nächstes setzen wir in IB den Delegaten unseres Fensters auf die Klasse LPWindowController und fügen dies in dieser Klasse hinzu:

- (void) windowWillClose:(NSNotification *)notification
{
    [self autorelease];
}

Und schließlich, wenn wir unser Fenster erstellen und anzeigen müssen, verwenden wir einfach die folgende Methode, anstatt "alloc/initWithWindowNibName:" auf LPWindowController aufzurufen.

LPWindowController *cont = [LPWindowController autoreleasingInstanceShowingWindow];
cont = nil;

Die zweite Zeile ist wichtig. Erstens beseitigt sie eine Warnung über "unused variable cont". Zweitens beseitigt sie die Gefahr eines baumelnden Zeigers. Sobald die Instanz von LPWindowController sich selbst freigibt, wird cont, wenn es nicht gelöscht ist, auf Speicherplatz verweisen.

Das ist jedenfalls mein empfohlener Ansatz für dieses Problem.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X