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?


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)
}

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.