ViewController replyToSelector: Nachricht an freigegebene Instanz gesendet (CRASH)

95

Ok, hier ist der Deal, ich hasse es, Fragen zu meinem Debugging und Abstürzen zu stellen. Weil ich sie normalerweise selbst erledige, aber ich kann mich einfach nicht darum kümmern , selbst nachdem ich bereits mehrere Fragen gesehen habe .

Ok, hier ist das Problem. Ich finde, dass meine App mit diesem Stack-Trace zufällig ein- und ausgeschaltet wird:

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

Wo ViewControllerkann variieren, manchmal hat der Ort, an dem mein Code abstürzt, KEINE Relevanz für diesen bestimmten ViewControllerund besitzt oder nennt ihn nicht.

Um diese Konsolenverfolgung zu erhalten, habe ich Zombies aktiviert, andernfalls würde ich überhaupt keinen Konsolendruck erhalten, sondern nur:, objc_msgSendwas ich weiß, bedeutet, dass ich etwas verschicke, das veröffentlicht wird. Aber ich kann nicht finden, wo das ist ... Ich stecke wirklich fest! Normalerweise debugge ich immer meine Abstürze, also bin ich wirklich festgefahren.

Auch dies stürzt an verschiedenen Orten zu unterschiedlichen Zeiten ein und aus. Und der Ort, an dem es abstürzt, hat fast keine Relevanz für die ViewController. Und ich finde das sehr verwirrend.

Benötigen Sie einen meiner Codes? Ich habe viele Dateien und da es an verschiedenen Orten abstürzt, wird das Verteilen meines Codes ein Chaos sein!

Ich habe ohne Glück versucht, symbolische Haltepunkte hinzuzufügen, und Zombies ist in der Instruments-Anwendung für iOS nicht verfügbar. Ich kann meine App nicht auf dem Simulator ausführen, da er nicht unterstützende Architektur-Frameworks enthält.

Vielen Dank an alle ...

MCKapur
quelle
Haben
self
Angenommen, die Art und Weise, wie Sie zu Ihren Ansichten übergehen, ist konsistent. Vielleicht können Sie uns ein oder zwei Beispiele zeigen. Wenn Sie Standard-Push / PresentViewController-Aufrufe ausführen, sollte es Ihnen gut gehen, aber ich sehe viele Leute hier, die Dinge wie das Zuweisen / Initiieren eines View-Controllers tun, aber dann kein Push / Present ausführen, sondern nur die Controller hinzufügen Ansicht als Unteransicht. Nur ein zufälliges Beispiel. Aber ohne Code können wir das nicht diagnostizieren. Hoffentlich helfen uns ein paar Ausschnitte dabei, herauszufinden, was los ist. Mal sehen.
Rob
Wie wäre es mit der Aktivierung symbolischer Haltepunkte? Versuchen Sie, diese hinzuzufügen: wiki.zemingo.com/index.php?title=Symbolic_Breakpoints
Stavash
@ RobertRyan Ich benutze presentModalViewController, ich füge es nicht als Unteransicht hinzu
MCKapur
In meinem Fall enthielt mein untergeordneter Ansichts-Controller eine WebView, und die untergeordnete VC war der Delegat für die scrollView der WebView. Ich musste die Delegatenreferenz während des Dealloc / viewWillDisappear manuell entfernen, sonst kam es zu diesem Absturz. Hoffe es hilft jemandem.
Dermot

Antworten:

169

Verwenden Sie Instrumente , um freigegebene Instanzfehler aufzuspüren. Profilieren Sie Ihre Anwendung ( Cmd ⌘+ I) und wählen Sie Zombies- Vorlage. Versuchen Sie nach dem Ausführen Ihrer Anwendung, sie zum Absturz zu bringen. Sie sollten so etwas bekommen:

Geben Sie hier die Bildbeschreibung ein

Klicken Sie auf den Pfeil neben der Adresse im Popover, um das Objekt anzuzeigen, das nach der Freigabe aufgerufen wurde.

Geben Sie hier die Bildbeschreibung ein

Sie sollten jetzt sehen, dass jeder geänderte Aufruf die Anzahl dieses Objekts beibehält. Dies kann daran liegen, dass Nachrichten direkt gespeichert / freigegeben sowie Autorelease-Pools geleert oder in NSArrays eingefügt werden.

In der RefCt- Spalte wird RetainCount angezeigt, nachdem die Aktion aufgerufen wurde, und Responsible Caller zeigt den Klassennamen und die Methode an, in der sie ausgeführt wurde. Wenn Sie auf eine Aufbewahrung / Freigabe doppelklicken, zeigen die Instrumente Ihnen die Codezeile an, in der dies ausgeführt wurde (Wenn dies nicht funktioniert, können Sie den Anruf überprüfen, indem Sie ihn auswählen und sein Gegenstück im Bereich " Erweiterte Details" auswählen ):

Geben Sie hier die Bildbeschreibung ein

Auf diese Weise können Sie den gesamten RetainCount- Lebenszyklus eines Objekts untersuchen und Ihr Problem wahrscheinlich sofort feststellen. Alles, was Sie tun müssen, ist, fehlende Aufbewahrung für die neueste Version zu finden .

Johnnywho
quelle
3
Das Problem ist möglicherweise nicht das neueste release. Das Problem ist jedes unausgeglichene release. Ich kann auch einfach ein Fehler bei retainetwas sein, auf das Sie einen Zeiger behalten und auf das Sie später verweisen.
Ken Thomases
1
Außerdem habe ich keine Vorlage für Zombie-Instrumente.
Dies
2
Oh, Zombies werden nur im iOS-Simulator bereitgestellt. Ich kann nicht im iOS-Simulator ausgeführt werden, einige meiner verwendeten Frameworks und Bibliotheken unterstützen die Architektur nicht
MCKapur
Nur eine kleine Notiz. Dies ist aus dem, was in xcode 5 neu ist. "Die Zombies-Instrumentenvorlage wurde in Xcode 5 erweitert und unterstützt jetzt die Verwendung auf Geräten. Für die Verwendung von Zombies auf Geräten ist iOS 7 erforderlich." Diese Notiz brachte Sie von mir und 2 Stunden meiner kostbaren Zeit ...
Nickfox
2
Was bedeutet es , wenn unser App stoppt Absturz und stoppt eine „Nachricht gesendet deallokierten Instanz“ Fehler geben , wenn wir es dieses Instrument Haken? (Es ist, als ob die "Krankheit" verschwindet, wenn der Patient einen "diagnostischen Test" erhält.)
Praxiteles
59

hatte ein ähnliches Problem. In meinem Fall musste ein viewController Navigationscontroller-Ereignisse abrufen, sodass er als Navigationscontroller-Delegat registriert wurde:

 self.navigationController.delegate = self;

Der Absturz tritt auf, wenn dieser Controller freigegeben wurde, aber immer noch der Delegat für den View-Controller war. Das Hinzufügen dieses Codes in dealloc hatte keine Auswirkung:

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

Da zum Zeitpunkt des Aufrufs von dealloc der Ansichts-Controller bereits aus der Ansichtshierarchie entfernt wurde, ist self.navigationController gleich Null, sodass der Vergleich garantiert fehlschlägt! :-(

Die Lösung bestand darin, diesen Code hinzuzufügen, um zu erkennen, dass der VC die Ansichtshierarchie verlässt, bevor er dies tatsächlich tut. Es verwendet eine in iOS 5 eingeführte Methode, um zu bestimmen, wann die Ansicht eingeblendet und nicht verschoben wird

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

Keine Abstürze mehr!

Software entwickelt
quelle
Ich auch danke - nur 4 Stunden Suche benötigt, um diesen Beitrag zu finden.
Daidai
Vielen Dank für die Veröffentlichung, hatte das gleiche Problem ^^
Tyron
Wie finden Sie Lösungen für solch irritierende Probleme? Hut ab !!
ViruMax
4

Für alle, die es nicht lösen können, sind hier einige andere Techniken:

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

Sie können Instrumente in Xcode 5 ausführen, indem Sie auf das Projekt-Popup-> Schema bearbeiten ... Profil -> Instrument klicken und Zuordnungen oder Lecks auswählen, dann Ihre App profilieren, Instrumente stoppen, auf die Info-Schaltfläche unter Zuordnungen klicken und "NSZombie-Erkennung aktivieren". .

Für die Nachrichten, die direkt aus dem com.apple.main-Thread stammen, wird dies jedoch wahrscheinlich nichts verraten.

Ich schlug über zwei Stunden lang mit dem Kopf darauf und die Antwort stellte sich als Überveröffentlichung heraus, die ich entdeckte, indem ich eine Kopie meines Projekts mit brutaler Gewalt auskommentierte, bis ich den Schuldigen fand:

[viewController release];
viewController = NULL;

Das Problem ist, dass Release die Variable nicht auf NULL setzt.

Das bedeutet, dass das Setzen auf NULL-Aufrufe erneut freigegeben wird, der Refcount dekrementiert und der Speicher sofort freigegeben wird, bis später die Variablen, die auf viewController verweisen, damit fertig sind.

Aktivieren Sie also entweder ARC oder stellen Sie sicher, dass Ihr Projekt konsistent Release oder NULL verwendet, jedoch nicht beide. Ich bevorzuge die Verwendung von NULL, da es dann keine Möglichkeit gibt, auf einen Zombie zu verweisen, aber es schwieriger macht, herauszufinden, wo Objekte freigegeben werden.

Zack Morris
quelle
4

Ich hatte gestern das gleiche Problem in iOS getroffen. Ich habe IAP in der Unteransicht "Info" der App erstellt und Transaction Observer in viewDidLoad "Info" hinzugefügt. Beim ersten Kauf kein Problem, aber nachdem ich zum Hauptfenster zurückgekehrt bin und die Unteransicht zum erneuten Kauf eingegeben habe, ist das Problem "Nachricht an freigegebene Instanz gesendet" aufgetreten und die App ist abgestürzt.

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

Nachdem ich Transaction Observer im Dealloc entfernt habe, ist das Problem behoben.

- (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];
}
Ouyang Yong
quelle
Es hat meinen Laufzeitabsturz behoben ... Ich habe ein zombieObjekt für InApp-Käufe erhalten. Nach vielen Stunden des Grabens fand ich diesen ... Ein großes Dankeschön Mann.
Mahendra
4

Ich hatte ein sehr ähnliches Problem und stellte fest, dass es an den eingestellten Navigationscontroller-Delegierten lag.

Das Folgende löste mein Problem,

- (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;
    }
}
thatzprem
quelle
Vielen Dank!! war das gleiche Problem hier.
Pegpeg
2

Hatte das gleiche Problem in OS X.

Um dies zu lösen, reicht nicht genug - (void)deallocMethode aus, wie @SoftwareEvolved bereits sagte. Ist aber leider - (void)viewWillDisappearnur ab Version 10.10 verfügbar.

Ich habe eine benutzerdefinierte Methode in meiner NSViewController-Unterklasse eingeführt, in der alle zombiegefährdenden Verweise auf Null gesetzt wurden. In meinem Fall waren das NSTableViewEigenschaften ( delegateund dataSource).

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

Das ist alles. Jedes Mal, wenn ich die Ansicht aus der Übersicht entfernen möchte, muss diese Methode aufgerufen werden.

Astoria
quelle
2

Ich hatte das gleiche Problem. Es war schwierig zu finden, welcher Delegat das Problem verursacht, da es keine Zeilen- oder Code-Anweisung anzeigt. Ich habe es also versucht. Vielleicht wird es für Sie hilfreich.

  1. Öffnen Sie die xib-Datei und wählen Sie im Eigentümer der Datei rechts das Menü "Verbindungsinspektor anzeigen". Delegierte werden aufgelistet, setzen Sie sie auf Null, was vermutet wird.
  2. (Wie in meinem Fall) Ein Eigenschaftsobjekt wie Textfield kann ein Problem verursachen. Setzen Sie daher seine Delegaten auf Null.
-(void) viewWillDisappear:(BOOL) animated{

[super viewWillDisappear:animated];

if ([self isMovingFromParentViewController]){

self.countryTextField.delegate = nil;

self.stateTextField.delegate = nil;

}

}
Nadim
quelle