Niestandardowy dealloc i ARC (Objective-C)

208

W mojej małej aplikacji na iPada mam funkcję „zmień język”, która korzysta z obserwatora. Każdy kontroler widoku rejestruje się u mojego obserwatora podczas jego viewDidLoad:.

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

Gdy użytkownik naciśnie przycisk „zmień język”, nowy język jest zapisywany w moim modelu, a obserwator zostaje powiadomiony i wywołuje updateUi:selektor zarejestrowanych obiektów.

Działa to bardzo dobrze, z wyjątkiem sytuacji, gdy mam kontrolery widoku w TabBarController. Dzieje się tak, ponieważ gdy pasek kart ładuje się, pobiera ikony kart ze swoich kontrolerów podrzędnych bez inicjowania widoków, więc viewDidLoad:nie jest nazywany, więc te kontrolery widoków nie otrzymują powiadomień o zmianie języka. Z tego powodu przeniosłem swoje registerObject:wywołania do initmetody.

Kiedy viewDidLoad:rejestrowałem się u mojego obserwatora, viewDidUnload:wyrejestrowywałem się. Ponieważ teraz się rejestruję init, wyrejestrowanie się z systemu ma sens dealloc.

Ale oto mój problem. Kiedy piszę:

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

Otrzymuję ten błąd:

ARC zabrania jawnego wysyłania wiadomości „dealloc”

Ponieważ muszę zadzwonić, [super dealloc]aby zapewnić prawidłowe czyszczenie nadklas, ale ARC zabrania tego, teraz utknąłem. Czy istnieje inny sposób uzyskania informacji o śmierci mojego obiektu?

Niku
źródło
Na marginesie - taka sytuacja może spowodować wyciek pamięci, który nie pojawiłby się w narzędziu Wycieki. Jeśli dataModel zachowuje odniesienie do obserwatora (co jest domyślną rzeczą w ARC, nawet w przypadku ivarów), dealloc nigdy nie zostanie wywołany, ponieważ liczba zatrzymań będzie większa od zera. Może być więc konieczne ręczne wyrejestrowanie obserwatora, aby umożliwić wywołanie dealloc.
Błażej Czapp,
Zaimplementowałem coś podobnego dla opcji prawo- i leworęcznych. Jedynym VC, który potrzebuje tego komunikatu, jest aktualnie wyświetlany. Inni patrzą na model w viewDidLoad lub viewDidAppear, aby wprowadzić zmiany w interfejsie. Może coś takiego działałoby lepiej.
Doug Watkins
@BlazejCzapp, ponieważ używa on UITabBarController, i powiedzmy, że UITabBarController zawsze będzie zawierał odniesienie do zarejestrowanego kontrolera (jak sądzę, że tak jest w przypadku kontrolerów „potomnych”), czy przeciek pamięci nadal będzie problemem? Nie wiem, kiedy zostanie przydzielony zarejestrowany kontroler. Dzięki
Objectif

Odpowiedzi:

419

Podczas korzystania z ARC po prostu nie wywołujesz [super dealloc]jawnie - kompilator obsługuje to za ciebie (jak opisano w dokumencie ARC Clang LLVM, rozdział 7.1.2 ):

- (void) dealloc
{
    [observer unregisterObject:self];
    // [super dealloc]; //(provided by the compiler)
}
justin
źródło
4
Jeśli widok zawiera odniesienie do obserwatora, a obserwator zawiera odniesienie do widoku, mamy odwołanie cykliczne. Zatem liczba odwołań do widoku jest większa niż 0 i deallocnigdy nie jest wywoływana. Czy warto zadzwonić [observer unregisterObject:self]dealloc? czego mi brakuje?
user443854
to chce pracy. ponieważ sam obserwator posiada odniesienie do kontrolera. zapobiegnie to przede wszystkim wezwaniu dealloca
hasan