Benutzerdefinierter Dealloc und ARC (Objective-C)

208

In meiner kleinen iPad-App habe ich eine "Sprache wechseln" -Funktion, die einen Beobachter verwendet. Jeder View Controller registriert sich während seiner Zeit bei meinem Beobachter viewDidLoad:.

- (void)viewDidLoad
{
    [super viewDidLoad];
    [observer registerObject:self];
}

Wenn der Benutzer auf die Schaltfläche "Sprache ändern" klickt, wird die neue Sprache in meinem Modell gespeichert und der Beobachter wird benachrichtigt und ruft einen updateUi:Selektor für seine registrierten Objekte auf.

Dies funktioniert sehr gut, außer wenn ich View-Controller in einem TabBarController habe. Dies liegt daran, dass beim Laden der Registerkartenleiste die Registerkartensymbole von den untergeordneten Controllern viewDidLoad:abgerufen werden, ohne die Ansichten zu initialisieren. Sie werden daher nicht aufgerufen, sodass diese Ansichtscontroller keine Benachrichtigungen über Sprachänderungen erhalten. Aus diesem Grund habe ich meine registerObject:Aufrufe in die initMethode verschoben .

Als ich mich viewDidLoad:bei meinem Beobachter registriert habe, habe ich mich immer viewDidUnload:abgemeldet. Da ich mich jetzt anmelde init, ist es sehr sinnvoll, sich abzumelden dealloc.

Aber hier ist mein Problem. Wenn ich schreibe:

- (void) dealloc
{
    [observer unregisterObject:self];
    [super dealloc];
}

Ich bekomme diesen Fehler:

ARC verbietet das explizite Senden von Nachrichten von 'Dealloc'

Da ich anrufen muss, [super dealloc]um sicherzustellen, dass die Superklassen ordnungsgemäß aufgeräumt werden, ARC dies jedoch verbietet, stecke ich jetzt fest. Gibt es eine andere Möglichkeit, sich zu informieren, wenn mein Objekt stirbt?

Niku
quelle
Nebenbei bemerkt - eine solche Situation kann zu einem Speicherverlust führen, der im Tool "Lecks" nicht angezeigt wird. Wenn das dataModel den Verweis auf den Beobachter beibehält (was unter ARC die Standardeinstellung ist, auch für ivars), wird der Dealloc niemals aufgerufen, da die Anzahl der Beibehaltungen größer als Null ist. Daher müssen Sie möglicherweise die Registrierung des Beobachters manuell aufheben, damit der Dealloc überhaupt aufgerufen werden kann.
Błażej Czapp
Ich habe etwas Ähnliches für Rechts- und Linkshänder implementiert. Die einzige VC, die die Nachricht benötigt, ist die aktuell angezeigte. Andere sehen sich das Modell in viewDidLoad oder viewDidAppear an, um Änderungen an der Benutzeroberfläche vorzunehmen. Vielleicht würde so etwas besser funktionieren.
Doug Watkins
@BlazejCzapp, da er einen UITabBarController verwendet, und sagen wir, der UITabBarController enthält immer einen Verweis auf den registrierten Controller (wie ich denke, ist dies bei seinen untergeordneten Controllern der Fall). Wird der Speicherverlust immer noch ein Problem sein? Ich sehe nicht, wann der registrierte Controller zugewiesen wird. Danke
Objectif

Antworten:

419

Wenn Sie ARC verwenden, rufen Sie einfach nicht [super dealloc]explizit auf - der Compiler übernimmt dies für Sie (wie im ARC-Dokument Clang LLVM, Kapitel 7.1.2 beschrieben ):

- (void) dealloc
{
    [observer unregisterObject:self];
    // [super dealloc]; //(provided by the compiler)
}
Justin
quelle
4
Wenn die Ansicht einen Verweis auf den Beobachter enthält und der Beobachter einen Verweis auf die Ansicht enthält, haben wir einen Zirkelverweis. Der Referenzzähler der Ansicht ist also größer als 0 und deallocwird niemals aufgerufen. Ist es sinnvoll, einen [observer unregisterObject:self]Dealloc einzuholen? Was vermisse ich?
user443854
das will Arbeit. weil der Beobachter selbst einen Verweis auf die Steuerung hält. das wird verhindern, dass der Dealloc überhaupt angerufen wird
hasan