2009-09-07 12 views
12

Sto cercando ulteriori chiarimenti dopo aver visto What is responsible for releasing NSWindowController objects?Chi possiede un NSWindowController, nella pratica standard?

Sto scrivendo una semplice applicazione di gestione dell'inventario per i miei nipoti. Ho una vista tabella che mostra il contenuto della loro "biblioteca", ecc. Per aggiungere un nuovo elemento alla libreria, fanno clic su un pulsante '+'. Questo pulsante apre una nuova finestra che richiede loro i dettagli dell'elemento e convalida l'input quando fa clic su "OK".

Tutto ciò funziona perfettamente. Tuttavia, ho una domanda sulla gestione della memoria. Per creare la nuova finestra, io uso il seguente codice:

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

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

non posso rilasciare (né autorelease) editorController alla fine del addNewItem:, perché niente altro fa riferimento editorController; se lo rilascio, la finestra scompare immediatamente. Tuttavia, desidero che il controller della finestra venga rilasciato una volta chiusa la finestra. In di Window Programming Guide Apple, ho letto il seguente:

Se si desidera che la chiusura di una finestra per rendere sia regolatore di finestra e finestra andare via quando non è parte di un documento , la sottoclasse di NSWindowController può osservare NSWindowWillCloseNotification o, come il delegato della finestra, implementare il metodo windowWillClose: e comprendono la seguente riga di codice nel tuo implementazione:

[self autorelease]; 

Ho utilizzato [self autorelease] nel metodo windowWillClose: del controller finestra. Funziona e non perde memoria. Tuttavia, sembra solo brutto; addNewItem: sembra che stia perdendo memoria e anche l'analisi statica la pensa così. I so che in realtà è gestito in windowDidClose:, ma si sente semplicemente sbagliato. Inoltre, il controllore di finestre si sta liberando senza aver mai mantenuto se stesso. Tutto ciò va contro le regole di gestione della memoria che ho imparato.

mia altra opzione è quella di mettere un Ivar sul controller genitore (o un NSWindowController o un NSMutableSet di NSWindowController s) e poi guardare per la NSWindowWillCloseNotification nel controller principale e rilasciarlo in risposta. Questo è più pulito, ed è probabilmente quello che farò. È anche un bel po 'di lavoro in più, che mi porta alle mie domande.

Sta guardando per il NSWindowDidCloseNotification il modo standard di farlo? Qual è il modo standard di gestire NSWindowControllers che viene creato e distrutto su richiesta? È il modo [self autorelease] l'opzione consigliata tradizionalmente, ed è solo ora che abbiamo un'analisi statica che questo è un problema?

risposta

5

Suona come la vostra finestra è modale, nel qual caso:

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

Ecco uno schema per le finestre non modali:

@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]; 
    } 
} 

Quindi chiunque voglia accedere o visualizzare la finestra può fallo attraverso il metodo di classe +sharedInstance.Se la finestra non è già visibile, viene creata, altrimenti ottengono la finestra attualmente visibile.

+0

Non l'ho eseguito come una finestra modale, ma penso che probabilmente dovrei. la versione sharedInstance ha senso per un panel di ispettori, credo. E se davvero avessi bisogno di avere più finestre aperte allo stesso tempo, probabilmente avrebbe senso per me trattenerle direttamente. Questo funziona per me. –

+0

Non credo che questa risposta sia corretta, poiché i metodi di classe non possono accedere alle variabili di istanza. In questo caso, il metodo di classe "sharedInstance" sta tentando di accedere a un iVar chiamato "_sharedInstance". Questo fallirà ogni volta. – Bryan

+0

'_sharedInstance' sarebbe una variabile statica, non un ivar. Questo è generalmente il modo in cui sono implementate le istanze condivise. –

0

La soluzione per le situazioni non modali pubblicate sopra non è corretta perché i metodi di classe non possono accedere a iVars. Ho risolto questo problema con la creazione di un metodo di classe (nel mio sottoclasse NSWindowController chiamato LPWindowController) che assomiglia a questo:

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

    return obj; 
} 

Il metodo di cui sopra restituisce un'istanza di LPWindowController con un conteggio di conservare 1. Essa mostra anche la finestra del controller . Questo è importante, perché altrimenti dovremmo fare affidamento sul chiamante per chiamare "showWindow:" per far apparire la finestra di LPWindowController. Se il chiamante non ha mai eseguito questa operazione (che probabilmente sarebbe un bug), il controller non verrebbe mai rilasciato. Forzando la finestra da visualizzare quando allochiamo/inizialo il controller, evitiamo questo errore.

successiva, in IB abbiamo impostato delegato della nostra finestra alla classe LPWindowController e aggiungere questo in quella classe:

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

E infine, quando abbiamo bisogno di creare e mostrare la nostra finestra, usiamo semplicemente il metodo di seguito invece di chiamare "alloc/initWithWindowNibName:" su LPWindowController.

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

La seconda riga è importante. Innanzitutto, elimina un avviso relativo alla "variabile non utilizzata". In secondo luogo, elimina il pericolo di un puntatore pendente. Una volta rilasciata l'istanza di LPWindowController, se cont non viene cancellato, punta alla memoria inutile.

In ogni caso, questo è il mio approccio consigliato a questo problema.

Problemi correlati