ViewController respondsToSelector: messaggio inviato all'istanza deallocata (CRASH)


95

Ok, ecco l'affare, odio porre domande sul mio debug e sugli arresti anomali. Perché di solito li gestisco da solo, ma non riesco a risolverlo , anche dopo aver visualizzato già più domande .

Ok, ecco il problema, trovo che la mia app si accende e si spegne in modo casuale con questa traccia dello stack:

*** -[ViewController respondsToSelector:]: message sent to deallocated instance 0x1e5d2ef0

Dove ViewControllerpuò variare, a volte il luogo in cui il mio codice va in crash, NON ha ViewControlleralcuna rilevanza per quel particolare e non lo possiede o lo chiama.

Inoltre, per ottenere quella traccia della console, ho abilitato Zombies, altrimenti non avrei ricevuto alcuna stampa dalla console, avrei solo ottenuto:, objc_msgSendche so significa che sto inviando un messaggio a qualcosa che viene rilasciato. Ma non riesco a trovare dove sia ... sono davvero bloccato! Di solito eseguo sempre il debug dei miei arresti anomali, quindi sono davvero bloccato su questo.

Ancora una volta, questo si blocca in luoghi diversi in momenti diversi, a intermittenza. E il luogo in cui si blocca non ha quasi alcuna rilevanza per il file ViewController. E lo trovo molto confuso.

Hai bisogno del mio codice? Ho molti file e poiché si blocca in luoghi diversi, distribuire il mio codice sarà un disastro!

Ho provato ad aggiungere punti di interruzione simbolici senza fortuna e Zombies non è disponibile nell'applicazione Instruments per iOS. Non riesco a eseguire la mia app sul simulatore in quanto dispone di framework di architettura non supportati.

Grazie a tutti...


hai guardato questa domanda: stackoverflow.com/questions/1585688/…
self,

Supponendo che il modo in cui passi alle tue opinioni sia coerente, forse puoi mostrarci un esempio o due. Se stai facendo chiamate push / presentViewController standard dovresti stare bene, ma vedo molte persone qui fare cose come allocare / inizializzare un controller di visualizzazione, ma poi non fare un push / present, ma piuttosto aggiungere semplicemente il controller vista come una vista secondaria. Solo un esempio casuale. Ma non possiamo diagnosticare questo senza un codice. Speriamo che alcuni frammenti ci aiutino a capire cosa sta succedendo, quindi vediamo.
Rob il

Che ne dici di abilitare i punti di interruzione simbolici? Prova ad aggiungere questi: wiki.zemingo.com/index.php?title=Symbolic_Breakpoints
Stavash

@RobertRyan Uso presentModalViewController, non lo aggiungo come sottoview
MCKapur

Nel mio caso, il mio controller di visualizzazione figlio conteneva una WebView e il VC figlio era il delegato per lo scrollView di WebView. Avevo bisogno di rimuovere manualmente il riferimento del delegato durante dealloc / viewWillDisappear o ho ottenuto questo arresto anomalo. Spero che aiuti qualcuno.
Dermot

Risposte:


169

Utilizza gli strumenti per rintracciare gli errori di istanza deallocati. Profila la tua applicazione ( Cmd ⌘+ I) e scegli il modello Zombi . Dopo che l'applicazione è in esecuzione, prova a bloccarla. Dovresti ottenere qualcosa del genere:

inserisci qui la descrizione dell'immagine

Fare clic sulla freccia accanto all'indirizzo nel popover per mostrare l'oggetto che è stato chiamato dopo che è stato deallocato.

inserisci qui la descrizione dell'immagine

Ora dovresti vedere ogni chiamata che è cambiata conserva il conteggio di questo oggetto. Ciò potrebbe essere dovuto all'invio diretto di messaggi di conservazione / rilascio, allo svuotamento di pool di rilascio automatico o all'inserimento in NSArrays.

La colonna RefCt mostra il keepCount dopo che l'azione è stata invocata e il chiamante responsabile mostra il nome della classe e il metodo in cui è stata eseguita. Quando fai doppio clic su qualsiasi ritenzione / rilascio, gli strumenti ti mostreranno la riga di codice dove è stato eseguito (se non funziona, puoi esaminare la chiamata selezionandola e scegliendo la sua controparte nel riquadro Dettagli estesi ):

inserisci qui la descrizione dell'immagine

Questo ti consentirà di esaminare tutto il ciclo di vita di keepCount dell'oggetto e probabilmente troverai subito il tuo problema. Tutto quello che devi fare è trovare la conservazione mancante per l'ultima versione .


3
Il problema potrebbe non essere l'ultimo release, in particolare. Il problema è qualsiasi squilibrato release. Posso anche semplicemente essere un fallimento a retainqualcosa a cui stai mantenendo un puntatore e facendo riferimento in seguito.
Ken Thomases

1
Inoltre, non ho un modello di strumenti Zombie, potrebbe essere perché sto usando Xcode Beta 4.5, nel frattempo
passerò

2
Oh, gli zombi sono forniti solo nel simulatore iOS. NON POSSO eseguire nel simulatore iOS, alcuni dei miei framework e librerie utilizzati non supportano l'architettura
MCKapur

Solo una piccola nota. Questo è tratto dalle novità di xcode 5. "Il modello di strumento Zombies è stato migliorato in Xcode 5 e ora supporta l'uso sui dispositivi. L'uso di Zombies sui dispositivi richiede iOS 7." Questa nota ti ha portato da me e 2 ore del mio prezioso tempo ...
nickfox

2
Cosa significa se la nostra App smette di bloccarsi e smette di dare un errore di "messaggio inviato a un'istanza deallocata" quando colleghiamo questo strumento ad essa? (È come se la "malattia" scompaia quando al paziente viene sottoposto un "test diagnostico".)
Prassitele

59

ha avuto un problema simile. Nel mio caso un viewController aveva bisogno di ottenere eventi di navigationController, quindi si stava registrando come delegato del controller di navigazione:

 self.navigationController.delegate = self;

L'arresto si verifica quando il controller è stato deallocato ma era ancora il delegato per il controller di visualizzazione. L'aggiunta di questo codice in dealloc non ha avuto alcun effetto:

-(void) dealloc
{
    if (self.navigationController.delegate == self)
    {
        self.navigationController.delegate = nil;
    }

perché nel momento in cui viene chiamato il dealloc, il controller di visualizzazione è già stato rimosso dalla gerarchia di visualizzazione, quindi self.navigationController è nullo, quindi il confronto è garantito! :-(

La soluzione era aggiungere questo codice per rilevare il VC che lasciava la gerarchia di visualizzazione appena prima che lo facesse effettivamente. Utilizza un metodo introdotto in iOS 5 per determinare quando la visualizzazione viene visualizzata e non spinta

-(void) viewWillDisappear:(BOOL) animated
{  
   [super viewWillDisappear:animated];
   if ([self isMovingFromParentViewController])
   {
      if (self.navigationController.delegate == self)
      {
           self.navigationController.delegate = nil;
      }
   }
}

Niente più crash!


Grazie anche a me - sono necessarie solo 4 ore di ricerca per trovare questo post.
daidai

Grazie per la pubblicazione, ha avuto lo stesso problema ^^
Tyron

Come trovate soluzioni a problemi così irritanti? Giù i cappelli !!
ViruMax

4

Per chiunque non sia in grado di risolverlo, ecco alcune altre tecniche:

https://stackoverflow.com/a/12264647/539149

https://stackoverflow.com/a/5698635/539149

https://stackoverflow.com/a/9359792/539149

https://stackoverflow.com/a/15270549/539149

https://stackoverflow.com/a/12098735/539149

Puoi eseguire gli strumenti in Xcode 5 facendo clic sul popup del progetto-> Modifica schema ... Profilo -> Strumento e scegli Allocazioni o Perdite, quindi profila la tua app, quindi interrompi gli strumenti, fai clic sul pulsante delle informazioni in Allocazioni e "Abilita rilevamento NSZombie" .

Tuttavia, per i messaggi che provengono direttamente dal thread com.apple.main, questo probabilmente non rivelerà nulla.

Ho sbattuto la testa su questo per oltre due ore e la risposta si è rivelata un rilascio eccessivo, che ho scoperto commentando una copia del mio progetto con la forza bruta finché non ho trovato il colpevole:

[viewController release];
viewController = NULL;

Il problema è che la versione non imposta la variabile su NULL.

Ciò significa che impostarlo su NULL chiama di nuovo il rilascio, decrementando il refcount e liberando la memoria immediatamente fino a quando le variabili che fanno riferimento a viewController hanno finito con esso.

Quindi abilita ARC o assicurati che il tuo progetto utilizzi costantemente release o NULL ma non entrambi. La mia preferenza è di usare NULL perché in questo caso non c'è alcuna possibilità di fare riferimento a uno zombi, ma rende più difficile trovare dove vengono rilasciati gli oggetti.


4

Avevo incontrato lo stesso problema in iOS ieri. Ho creato IAP nella sottoview "About" dell'App e ho aggiunto Transaction Observer in viewDidLoad "About". Quando acquisto per la prima volta, nessun problema, ma dopo essere tornato alla finestra principale e aver inserito nuovamente la sottoview per l'acquisto, si è verificato il problema "messaggio inviato all'istanza deallocata" e l'app si è bloccata.

- (void)viewDidLoad
{
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];                                           object:nil];
}

Dopo aver rimosso Transaction Observer in dealloc, il problema è stato risolto.

- (void)dealloc
{
    // Even though we are using ARC, we still need to manually stop observing any
    // NSNotificationCenter notifications.  Otherwise we could get "zombie" crashes when
    // NSNotificationCenter tries to notify us after our -dealloc finished.

    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

Ha risolto il mio crash di runtime ... Stavo ricevendo zombieoggetti per gli acquisti inApp. Dopo molte ore di scavi ho trovato questo ... UN GRANDE GRAZIE Uomo.
Mahendra

4

Ho avuto un problema molto simile e ho capito che era dovuto ai delegati del controller di navigazione impostati.

Quanto segue ha risolto il mio problema,

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if (self.navigationController.delegate != self) {
        self.navigationController.delegate = self;
    }
}

-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    if (self.navigationController.delegate == self) {
        self.navigationController.delegate = nil;
    }
}

Grazie!! era lo stesso problema qui.
pegpeg

2

Ha avuto lo stesso problema in OS X.

Per risolvere questo - (void)deallocmetodo non basta come ha già detto @SoftwareEvolved. Ma sfortunatamente - (void)viewWillDisappearè disponibile solo sulla versione 10.10 e successive.

Ho introdotto il metodo personalizzato nella mia sottoclasse NSViewController in cui impostare tutti i riferimenti pericolosi per zombi a zero. Nel mio caso erano NSTableViewproprietà ( delegatee dataSource).

- (void)shutdown
{
  self.tableView.delegate = nil;
  self.tableView.dataSource = nil;
}

È tutto. Ogni volta che sto per rimuovere la vista dalla superview è necessario chiamare questo metodo.


2

Ho avuto lo stesso problema È stato difficile trovare quale delegato causa il problema, perché non indica alcuna riga o istruzione di codice Quindi ho provato in qualche modo, Forse ti sarà utile.

  1. Apri il file xib e dal proprietario del file, seleziona "mostra l'ispettore delle connessioni" nel menu a destra. I delegati sono elencati, impostarli a zero che sono sospettati.
  2. (Come il mio caso) Oggetto proprietà come Textfield può creare problemi, quindi imposta i suoi delegati su zero.
-(void) viewWillDisappear:(BOOL) animated{

[super viewWillDisappear:animated];

if ([self isMovingFromParentViewController]){

self.countryTextField.delegate = nil;

self.stateTextField.delegate = nil;

}

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.