2009-06-11 7 views
7

C'è un modo per testare un'istanza c-obiettivo per essere deallocata/liberata (mantenere il conteggio == 0) ??Objective-C - Test per l'istanza dell'oggetto deallocata/liberata

Ad esempio, l'oggetto A ha un riferimento (puntatore) all'oggetto B, ma l'oggetto B può essere liberato in livelli di memoria bassi, come faccio a verificare il riferimento B per essere sicuro che sia stato deallocato ??

@interface A : NSObject { 
    B b; 
} 

@implementation A { 

- (void) someAction:(id) sender { 
    //is b previously dealloced?? 
    if ..... ???? { 
     b = [[B alloc] init]; 
    } 
    // continue 
} 
} 

Grazie !!

+0

Sembra che questo articolo possa mostrarvi come farlo: [Esegui codice nella deallocazione di qualsiasi oggetto] (http://blog.slaunchaman.com/2011/04/11/fun-with- the-objective-c-runtime-run-code-at-deallocation-of-any-object) – Oscar

risposta

11

Non è possibile verificare se un oggetto è stato deallocato poiché, ovviamente, l'oggetto non è lì per parlare più. Se si imposta su zero quando lo si rilascia (ad esempio, facendo self.b = nil), tuttavia, è possibile verificare nil e creare l'oggetto.

+1

questo è il problema, non rilascio l'oggetto esplicitamente, è rilasciato dalle classi framework e questo non capita in tempi prevedibili (ad esempio didReceiveMemoryWarning: chiamate di metodo) quindi ho bisogno di verificare se il mio riferimento (puntatore) sta ancora puntando a un'istanza valida, in caso contrario, allocare e iniziarne uno nuovo. – jlpiedrahita

+0

Quale classe framework rilascia la variabile di istanza di questa classe? Perché questa classe non possiede il suo stesso ivar? Penso che potrebbe essere necessario fornire maggiori informazioni nella domanda. Come ha detto Alex, i tuoi attributi non dovrebbero scomparire misteriosamente. – Chuck

2

Se si mantiene b correttamente, non sarà rilasciato in condizioni di memoria insufficiente.

Che è, a meno che non si sta deallocando da soli, in questo caso, è importante che si rimuove manualmente tutti i riferimenti ad esso prima di farlo (sostituendolo con nil)

In tal caso, è sufficiente testarlo per il valore nil farà:

if (nil == b) 
    { 
    reallocate b; 
    } 

Se sembra che gli oggetti vengono deallocate automaticamente, allora avete bisogno di rivedere il codice per verificare che avete conservato sufficientemente.

0

Si potrebbe provare a inserire messaggi NSLog negli oggetti dealloc metodo. Questo ti dirà almeno quando l'oggetto verrà rilasciato.

+0

Che non funzionerà per un test in codice per vedere se l'oggetto è stato deallocato. Nella migliore delle ipotesi, sarebbe utile per il debug che il codice di conservazione relativo a B fosse (probabilmente) corretto. –

3

Poiché la variabile b è completamente interna alla classe A, e non è dichiarato come @public (il valore predefinito è @protected), il modo migliore per sapere se b è stato deallocato è quello di rilasciarlo e impostare il puntatore nil. In questo modo, puoi semplicemente controllare if (b == nil) e creare una nuova istanza, se necessario.

La domanda più grande, tuttavia, è ciò che è la vera natura e il comportamento della memoria di b. Tu affermi che "l'oggetto B può essere liberato in livelli di memoria bassi", ma non spiega perché. Se stai usando gli idiomi standard per retain-release in Objective-C, penserei che sarebbe A a determinare se B dovrebbe essere deallocato, dal momento che sta creando una nuova istanza. Se non si intende che A effettui tali decisioni, consentendogli di assegnare una nuova B, si verificheranno confusione nella proprietà e errori di memoria lungo la strada.

Se A non è responsabile di B, e se siete su Leopard (o oltre) e hanno attivato la raccolta dei rifiuti, ciò che si può desiderare è un azzeramento riferimento debole. Viene dichiarato utilizzando __weak prima di una dichiarazione di variabile di istanza e non impedisce al garbage collector di raccogliere l'oggetto a cui punta. (Un riferimento "forte" è l'impostazione predefinita e il garbage collector non rilascia deallocolo che può tracciare da una radice attraverso solo riferimenti forti.) Inoltre, il GC imposterà automaticamente i riferimenti deboli a 0 se/quando l'oggetto è deallocato.

Tornando alla "domanda più grande", a meno che b sia già un riferimento debole e GC sia attivo, (e alcune altre condizioni sono in attesa), il sistema non rilascia automaticamente B per te.Se il motivo della deallocazione di b è che le istanze di B crescono nel tempo, (come una cache di articoli non disponibili), sarebbe molto meglio avere un modo per svuotare B. Ad esempio, le raccolte mutabili in Foundation hanno un metodo -removeAllObjects. Un simile approccio eviterebbe la maggior parte della confusione sul fatto che esista ancora b ed è molto più efficiente di (de) allocare più volte gli oggetti.

+0

I tag dicono Cocoa Touch, quindi non è su Leopard. – Chuck

+0

Uno dei tag è anche "Cocoa", e la domanda non specificava l'iPhone, quindi è meglio essere generale e qualificarsi con "if" per essere utile a coloro che potrebbero essere su Leopard. –

13

Se si imposta la variabile di ambiente NSZombieEnabled, gli oggetti dealloced diventano istanze di NSZombie. Questi vengono lanciati quando vengono successivamente messaggati, causando il blocco e la masterizzazione del codice, esattamente ciò di cui hai bisogno per eseguire il debug di questa situazione.

http://www.cocoadev.com/index.pl?DebuggingAutorelease

Aggiornamento: Per XCode 4.0 vedere How to enable NSZombie in Xcode?

+0

Wow, proprio quello di cui avevo bisogno oggi. Grazie! –

-3

fosse un lavoro "try-catch"?

@try { 
     [b description]; // test it... 
} 
@catch (NSException * e) { 
    NSLog(@"Exception: %@", e); 
} 
@finally { 
    NSLog(@"finally"); 
} 
+0

Sarebbe ma questa è la correzione del povero – Mel

+1

in modo sicuro chiamando un messaggio su un'istanza dealloced NON gira una normale eccezione piuttosto che un sigbart. –

+2

-1 per l'istanza deallocated NON genera un'eccezione. – Raptor

Problemi correlati