5

Wie ich es verstehe, müssen wir Verweise auf unsere Cocoa Objekte halten, wenn sie mit ihnen in Monotouch handelt. Der Grund dafür ist, dass die ObjC-Laufzeit möglicherweise noch Verweise auf die Objekte enthält, und wenn wir keine "MonoTouch-Verweise" auf ihnen haben, könnten sie Müll gesammelt werden, was zu einem EXC_BAD_ACCESS führt, sobald die ObjC-Laufzeit versucht, auf sie zuzugreifen .Release/verfügt über einen UIViewController in Monotouch

Sag mal, haben wir zwei UIViewController Unterklassen, VC1 und VC2. Wenn der Benutzer auf eine Schaltfläche auf VC1 klickt, navigiert die Benutzeroberfläche zu VC2, und der Benutzer kann vor und zurück navigieren. Wenn ich jedes Mal, wenn der Benutzer zu ihm navigiert, eine neue Instanz von VC2 erstelle, gehen die Verweise auf die alten Instanzen verloren. Daher werden sie als Müll gesammelt und die App stürzt beim nächsten Mal ab, wenn ein didReceiveMemoryWarning an die UIViewControllers weitergegeben wird.

Wie kann ich die alten Referenzen freigeben, so habe ich nicht jedes Mal die gleiche Instanz von VC2 verwenden? Dispose schien nicht genug zu sein.

Antwort

6

Wie ich es verstehe, müssen wir Referenzen zu unseren Cocoa-Objekten enthalten, wenn wir sie in MonoTouch behandeln.

Nicht ganz. MonoTouch verwaltet Instanzen behalten einen Verweis auf native Instanzen. Solange die verwaltet Instanz existiert die nativen Instanz wird am Leben sein (da sie Referenz gezählt sind und Monotouch wird Release nicht Bezug ist).

IOW Ihr Bedarf Verweis auf die Monotouch zu halten verwaltet Instanzen, solange ihr nativen Teil erforderlich ist.

Der Grund dafür ist, dass die ObjC Laufzeit noch Verweise auf die Objekte halten könnte ... sie Müll gesammelt werden kann,

Native (Objective C) Instanzen Referenz gezählt, nicht Müll gesammelt . Einheimische Instanzen erst ihre Referenzzähler Reichweite 0 freigegeben werden (die während happen nicht ein zugehöriges verwaltet Instanz vorhanden ist);

Auch nativen Instanzen können Verweise auf andere einheimische Instanzen halten. Nicht alle nativen Instanzen haben eine entsprechende verwaltet Instanz.

was zu einem EXC_BAD_ACCESS führt, sobald die ObjC-Laufzeit versucht, auf sie zuzugreifen.

Das wird nicht passieren, zumindest nicht so. OTOH, es ist schwer zu sagen, was in deinem Fall passiert (ohne den Code und/oder die Abstürze zu sehen).

ich Verdächtiger Sie entsorgen (manuell oder nicht) Ihre verwaltet Instanzen, bevor sie ihre Arbeit abgeschlossen haben. Hier ist eine vereinfachte von dem, was passieren könnte:

  • Sie erstellen verwaltet MT.X Instanz (beispielsweise ein UIView);
  • erstellt und Referenz native X (native Referenzzahl == 1);
  • Sie überschreiben ein Ereignis (oder fügen Sie einen Delegaten ...) `ViewWillUnload 'auf MT.X (die auch nativ vorhanden ist);
  • weisen Sie die MT.X-Instanz einer anderen (verwalteten) Instanz zu, z. ein UIViewController;
  • die nativerUIViewController wird eine Referenz auf die nativer X (native Referenzzählwert == 2) hinzuzufügen; happilly
  • Anwendung ausführt ...
  • Sie stoppen einen Verweis auf die MT.X Instanz (z.B. die Variable null oder eine andere Instanz festgelegt);
  • da gibt es keinen Hinweis auf MT.X mehr der Garbage Collector verfügen die Instanz verwaltet, Dispose Aufruf, die wird reduzieren die Bezugnahme auf nativen X (native Zählung Referenz == 1). Aber die native Instanz wird nicht freigegeben, da sie immer noch vom View-Controller referenziert wird (nicht 0);
  • die UIViewController tut etwas, das nativ X.ViewWillUnload (z. B. versucht es, eine neue UIView laden) löst;
  • seit X existiert noch nativ (ref Zahl == 1) wird es nennen es ViewWillUnload ist die Instanz zurück zum verwaltet werden versuchen, gehen ... das angeordnet war.

Die Lösung für dieses Problem ist, dass Sie, um sicherzustellen, sicherzustellen, sind Instanz, bis ihre nativen Teil abgeschlossen haben ihre Arbeit nicht entsorgen verwaltet.

+1

Vielen Dank, aber ich bin mir sicher, dass ich keine Referenzen mehr habe. Die einzige verwaltete Sache, die 'VC2' referenziert, ist meine' VC1'-Instanz. Wenn ich diese Instanz auf null setze, sollte die Referenzzahl auf der nativen 'VC2'-Instanz 0 sein. Aber es scheint, dass iOS einen Verweis auf die Controller für die Verteilung von 'didReceiveMemoryWarning'-Nachrichten, da, sobald es eine 'didReceiveMemoryWarning'-Nachricht gibt, meine App abstürzt. – cheeesus

+0

Sie haben wahrscheinlich keine ** verwalteten ** Referenzen, aber Sie könnten durchaus ** native ** Referenzen (zwischen ihnen oder deren Eltern) haben. Sie sollten sie nicht aufheben (verwaltete Seite), bevor Sie sicher sind, dass ihr Lebenszyklus (native Seite) abgelaufen ist, da sie wieder in eine entsorgte (verwaltete) Instanz zurückrufen kann. Wenn Sie einen kleinen Testfall haben (oder extrahieren können), öffnen Sie einen Fehlerbericht unter http://bugzilla.xamarin.com und wir überprüfen den Code. – poupou

+0

Ok, ich versuche es zu isolieren. Danke für Ihre Hilfe. – cheeesus

1

Ich habe die gleiche Situation in meinem app und GC sammelt korrekt Objekte. Mit anderen Worten, ich hatte nie ein Problem, einfach die Referenz auf einen VC zu löschen und GC den Rest erledigen zu lassen.

Allerdings habe ich Probleme, wenn für Dispose Methode aufgerufen, wie Sie tun. Es scheint, wir sollten das nicht manuell machen. Stattdessen sollten wir darauf warten, dass GC Objekte sammelt und Ressourcen freigibt. Base NSObject Klasse hat einen Aufruf an Dispose in seinem Finalizer, so dass alle nicht verwalteten Ressourcen freigegeben werden, sobald Objekt gesammelt wird.

Sie können auch GC.Collect in einigen der Root VCs DidReceiveMemoryWarning Methode aufrufen.