Ich sehe gelegentlich Abstürze mit einem Stack-Trace wie folgt:
%Vor% Leider ist es ziemlich zufällig zu reproduzieren. Hat jemand Ideen, was einen solchen Absturz verursachen könnte? Es hilft nicht, dass niemand -_queueForDealloc:
schon einmal im Internet erwähnt hat!
Ich habe eine vage Erinnerung an ein ähnliches Problem in der Vergangenheit, bei dem dies ein Symptom für die Freigabe eines verwalteten Objekts war, während noch KVO-Beobachter angeschlossen waren. Jeder stimmt zu?
Nachdem das Problem endlich auf einer Entwicklungsmaschine reproduziert werden konnte, scheint dieser Absturz ein Nebeneffekt einer früheren Ausnahme beim Kontext-Teardown zu sein.
Die Reihenfolge der Ereignisse ist ungefähr wie folgt:
MOC
wird freigegeben, daher ist es an der Zeit, den Inhalt zu löschen MOs
in Fehler * MO
in einen Fehler umgewandelt wird, sendet KVO-Benachrichtigungen MO
trifft
MO
s werden freigegeben, aber die Ausnahme hat Core Data in einem unerwarteten Zustand hinterlassen, so dass die MO
Freigabe fehlschlägt Kurz gesagt besteht das eigentliche Problem darin, dass Beobachter den Kontext überleben; erlaube ihnen nicht! Jedes Objekt, das MO
beobachtet, sollte wahrscheinlich auch eine starke Referenz auf MOC
haben, wie NSObjectController
und Freunde tun.
* Ich habe beim Testen festgestellt, dass Core-Daten dies oft in einem Hintergrundthread tun, vermutlich um den Hauptthread nicht zu blockieren
MOC
- Kontext des verwalteten Objekts
MO
- verwaltetes Objekt
-_queueForDealloc:
ist eine nicht dokumentierte interne Methode. Es zeigt sich von Zeit zu Zeit in Stapeln, aber es ist nichts, womit wir direkt umgehen.
Ihr Problem wird höchstwahrscheinlich durch die Überlassung eines managedObject verursacht. Ein managedObject wird stark von einem Kontext beibehalten, der das Objekt einfügt, aktualisiert oder ändert. Wenn Sie also die objekteigene Aufbewahrung mikromantieren, können Sie sie vor der Freigabe des Kontexts überladen. Dies führt dazu, dass das verwaltete Objekt scheinbar zufällig verschwindet. Umgekehrt können Sie ein Objekt beibehalten, das nach dem Löschen durch den Kontext bestehen bleibt.
Ich ermutige Menschen, verwaltete Objekte nicht zu behalten, aber wenn Sie dies tun, legen Sie ihnen eine Klasseneigenschaft oder eine Sammlung wie ein Array oder einen Satz. Auf diese Weise wird die Aufbewahrung für Sie erledigt.
Wir sind auf ein ähnliches Problem gestoßen, als wir einen privaten Kontext für verwaltete Objekte innerhalb von NSOperation
verwendet haben. Wir haben damit umgegangen, indem wir alle Parameter abgeschwächt und eine private @autoreleasepool
verwendet haben. Ich werde weiter unten näher ausführen.
Unsere aktuelle Konfiguration hat eine NSOperationQueue
, die eine lang laufende Berechnung hat, die wir im Hintergrund machen. Die Operation erstellt zuerst einen privaten verwalteten Objektkontext mit dem übergeordneten Set als Hauptobjektkontext und geht und ruft ihre Objekte ab.
In der Zwischenzeit haben wir ein separates NSOperationQueue
an anderer Stelle, das neue Daten von unserem Server synchronisiert und möglicherweise Objekte hinzufügt, aktualisiert oder entfernt, die von unserer Rechenoperation verwendet werden.
Wir sahen zuerst eine Menge dieser Abstürze in der Wildnis und die einzige Möglichkeit, sie lokal zu reproduzieren, besteht darin, dass sowohl Rechen- als auch Synchronisierungsoperationen kontinuierlich ausgeführt werden und nach 5 bis 10 Minuten ein Absturz ähnlich einem der beiden erscheinen würde unten:
%Vor%Wir haben den Code mehrfach überprüft und konnten nicht feststellen, warum er abgestürzt ist. Wir haben versucht, NSZombies zu aktivieren, aber wir hatten keinen Speicher mehr, lange bevor wir eine Repro erhalten konnten.
Was wir am Ende gemacht haben, sind die folgenden 2 Dinge:
@autoreleasepool
In unserem [privateObjectContext performBlockAndWait:^{…}]
, das sich in unserem NSOperationBlock
befindet, haben wir den gesamten Code in ein @autoreleasepool{…}
gehüllt. Auf diese Weise werden alle NSManagedObjects, die während dieses Codeblocks abgerufen wurden, zur Freigabe markiert, bevor sie performBlockAndWait verlassen.
schwächen / verstärken
Alle Parameter, die NSManagedObjects enthalten, wurden vor dem Übergeben in den Block abgeschwächt und im Block einmal verstärkt. Auf diese Weise können wir sie loslassen, wenn sie veraltet sind, während wir auf den Start von NSOperation
warten. Hier ist ein guter Artikel über die Funktionsweise von weakify / strongify: Ссылка
Ich habe eine andere Lösung, um diesen Fehler zu beheben. In Beispielen sehen MOC-Eigenschaften für ARC wie (nur gelesen, stark, nichtatomisch) aus
Nach Wochen des Tanzens über diesen Zeit-zu-Zeit-Absturz habe ich eine Lösung für osx (entferne einfach nicht-atomare).
Jetzt ist es perfekt, alle Abstürze gehen aus.
Tags und Links cocoa core-data nsmanagedobject