2012-02-09 9 views
35

Ho un UIViewController che viene inserito in un controller contenitore e quindi estratto, e utilizzando lo strumento di allocazione, posso vedere che il controller della vista viene distrutto in seguito. Tuttavia, un punto di interruzione nel dealloc del controllore non viene mai raggiunto. Qualcuno sa perché dealloc non viene chiamato? È possibile che ARC distrugga un oggetto senza chiamare dealloc?Dealloc non viene chiamato sull'app ARC

Inoltre, ho disabilitato NSZombies (alcuni hanno detto che possono causare dealloc non sparare).

Edit:

Dealloc non fa molto, stampa solo per la console, e non è mai viene chiamato:

- (void)dealloc { NSLog(@"Deallocating..."); }

non posso postare il controller-it contenitore è proprietario e troppo complicato. Dealloc è chiamato in modo coerente su alcuni controller e non su altri. Se riesco a trovare il tempo cercherò di pubblicare una versione semplificata che riproduca il problema.

Esiste un modo per verificare che NSZombies sia disabilitato?

Edit2

sto postando uno screenshot da strumenti; mi sembra come se stesse dislocando correttamente.

enter image description here

+1

dovrebbe essere sempre chiamati, anche sotto ARC. Non puoi includere [super dealloc], ma ARC lo aggiungerà per te. Forse condividi il codice per questa classe? – picciano

+0

Esistono metodi nel metodo dealloc? – zaph

+1

Dovresti pubblicare il codice '- (void) dealloc {}'. – NJones

risposta

19

Se dealloc non viene chiamato dal VC, poi ci avrei scommesso c'è un riferimento circolare da qualche parte nel codice, che impedisce ARC dalla chiamata dealloc.

Alcune cose da controllare:

  1. Avete un oggetto istanziato che i riferimenti risalgono al VC?
  2. Se è necessario fare riferimento al VC, assicurarsi di aver utilizzato l'attributo "__unsafe_unretained" o "debole" (iOS5 +) in modo che il ciclo di conservazione non si verifichi.

Sono stato stroncato nel culo quando le mie dichiarazioni dei delegati non hanno utilizzato __unsafe_unretained.

88

Ho appena imbattuto in un problema simile. Hai dei blocchi in cui ti stai riferendo a "te stesso"? Avevo alcuni blocchi per l'osservazione delle notifiche nel mio init, in cui mi riferivo a "me stesso". Sotto ARC self viene mantenuto in blocchi. Il mio dealloc non veniva chiamato ed era lì che stavo rimuovendo l'osservazione.

Il trucco è creare un riferimento __weak (iOS 5+) o __unsafe_unretained (iOS 4.x) al proprio "sé" e utilizzarlo per accedere a self o a qualsiasi _iVars (questi causeranno il "sé" da conservare come bene) nel blocco. Ecco un esempio.

__unsafe_unretained TableViewController *weakSelf = self; 
[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) { 
     if (weakSelf.tableView) { 
      [weakSelf.tableView reloadData]; 
     } 
    }]; 
+0

Dopo aver riesaminato il codice di molti dei codici migrati (dai progetti non arc ai progetti arc), posso confermare che questa è una fonte importante di ritenzione indesiderata -imposta. Alla fine: un blocco è utile ed è facilmente creato, giusto! – leviathan

+0

Non annullando la registrazione dell'osservatore, significa che scatterà in risposta alla notifica * per sempre *, anche dopo che 'self' è sparito da tempo. E se aggiungi questo osservatore più volte, ogni volta che questa notifica accade, sparerà a più osservatori inutili, per sempre. Questo non può essere una buona pratica di programmazione. – user102008

+7

Per semplicità possiamo usare '__weak typeof (self) weakSelf = self;' – Vive

16

Anche con ARC è possibile controllare il conteggio dei riferimenti manualmente:

CFIndex rc = CFGetRetainCount((__bridge CFTypeRef)myObj); 

È possibile sapere con certezza se il codice è appeso in un ciclo di memoria.

+0

Sono d'accordo con @Dean Liu - Gli strumenti non resistono, ho il sospetto che non sia stato deallocato a causa di un ciclo di memoria. Di tanto in tanto mi vengono a mancare i cicli con Blocks, specialmente se il blocco fa riferimento a "sé", è molto facile da fare. – jbbenni

+0

grazie che è molto utile! –

+3

Questo ha aiutato! (Sarebbe sicuramente bello se esistesse un metodo di chiamata di funzione corrispondente che forniva un elenco di tutti gli oggetti che facevano riferimento a un oggetto). –

9

Ecco un altro suggerimento (mi è successo):

tl; dr: Guardate le vostre variabili d'istanza classe così, non solo le proprietà della classe. Stai allocando una variabile di istanza nel codice e non la imposti in nil in seguito?

Avevo una classe con un gruppo di proprietà (@property (nonatomic, strong) e @property (nonatomic, weak)) nel suo file di intestazione. Ho commentato quelle proprietà una per una per vedere se questo cambierà qualcosa. Io non l'ho fatto. La classe principale non era ancora stata dislocata. Quindi il problema non era nelle proprietà.

Quello che ho fatto in seguito è stato esaminare le variabili di istanza. Ho avuto una variabile di istanza (che era un UIViewController), che ho creato su viewDidLoad. Questo mai ha ottenuto dealloc-ed!

Quando ho rimosso questa variabile, abbastanza sicuro, la mia classe principale si chiamava dealloc.

Quindi, poiché questo non è stato deallocato, anche la mia classe principale non è stata deallocata. Lo spostamento di tale variabile di istanza come una proprietà ha risolto il problema per me.

Domanda: Non sono sicuro del perché questo accada però. Il sistema operativo ha un migliore controllo sulle proprietà di una classe rispetto alle variabili di istanza? Sembra un po 'strano che la classe genitrice che contiene la variabile di istanza non venga rilasciata a causa della sua variabile di istanza.

21

Nel mio caso era NSTimer. Mantiene il suo obiettivo quindi è necessario invalidare il timer quando hai finito con il controller di visualizzazione.

13

Il mio problema era delegato.

Controlla i tuoi delegati! La proprietà delegato dovrebbe avere weak specificato:

@property (weak, nonatomic) id<SomeProtocol> delegate;

Problemi correlati