2009-06-16 9 views
9

Widziałem kod (prawdopodobnie własny przykładowy kod Apple) napisany w taki sposób, że uwalnia ivar w dealloc i ustawia właściwość w viewDidUnload.Czy konieczne jest zwolnienie ivar i ustawienie zsyntetyzowanego ivar na zero w tym samym czasie?

np.

- (void)viewDidUnload 
{ 
    self.navigationController = nil; 
} 

- (void)dealloc 
{ 
    [_navigationController release]; 
} 

Dlaczego są one w dwóch miejscach? Ponadto, dlaczego ustawić zero w jednym i zwolnić w innym. Wygląda na to, że self.property = zero zajmowałoby się wszystkim, odkąd zwolniłoby i ustawiło wartość ivar na zero.

Odpowiedz

5

Masz rację: rzeczywiście możesz zrobić self.property = nil wszędzie, łącznie z dealloc. Jedynym minusem jest to, że jeśli metoda settera robi coś bardziej skomplikowanego niż tylko zwolnienie ivar, może się okazać, że próbujesz uzyskać dostęp do innych pól, które zostały już wydane, itp.

Co do tego, dlaczego również wypuszczasz gniazdo w viewDidUnload to jest optymalizacja pamięci. Ponieważ rzeczy, które publikujesz w viewDidUnload, zostaną przywrócone, gdy widok zostanie ponownie załadowany, zwolnienie ich zwolni pamięć w sytuacjach z małą ilością pamięci.

+0

Dzięki, więc w tym przypadku kod viewDidUnload mógł użyć tego samego kodu jako dealloc do zwalniania obiektu, tj. [_navigationController release] zamiast ustawić go na zero, prawda? – Boon

+1

Tak, ale nie rób tego. Użyj akcesora wszędzie z wyjątkiem -dealloc. Używanie akcesorów w -dealloc jest kontrowersyjne z przyczyn podanych przez Daniela (Apple również nie jest pewne, co zalecają). Po prostu przyzwyczajaj się do wypuszczania wszystkich swoich zachowanych ivarów w -określeniu. Nie zakładaj się, że możesz to zrobić za ciebie. A kiedy coś wypuścisz, ustaw go na zero. Znaczna część ObjC jest bez siatki bezpieczeństwa; dobre nawyki sprawiają, że programy działają, ponieważ kompilator cię nie uratuje. (OK, może Clang nareszcie nas uratuje, ale tylko użyje swojej mocy na dobre.) –

0

Jeśli polegasz na zbieraniu śmieci (dostępnym w Objective-C 2.0), ustawienie ivar na nil i wywołanie release osiągnie ten sam efekt.

Zgaduję, że kod, na który patrzysz, zarządza pamięcią przy pomocy release i ustawia ją tylko na nil, abyś później nie próbował uzyskać dostępu do obiektu, który już nie istnieje. nil to więcej niż zarządzanie pamięcią, gdy nie polegasz na GC.

+0

Nie całkiem - - [Wydanie anObject] nic nie zrobi (to jest nop) pod GC, a ustawienie na zero pozwoli na zbieranie śmieci aby ostatecznie uwolnić obiekt (usuwa odniesienie), chyba że ivar jest zdefiniowany jako słabe odniesienie. – xtophyr

1

Polecenia Apple, które nie wywołują setterów w procedurach init, a zwłaszcza dealloc.

Wynika to z faktu, że obiekt jest tylko częściowo skonfigurowany w tym czasie, a setery mogą mieć obserwatorów dołączonych do nich, lub mogą być przesłonięte przez podklasy, a poza tym mieć niepożądane wpływy podczas dealloc, lub mogą być zdezorientowani podczas init z częściowo skonfigurowanym obiektem.

Stąd normalnie używać:

_navigationController = [[NavController alloc] init]; 

kodu styl w rutynowych init kod

[_navigationController release]; 

stylu w swojej dealloc i ustawiające w innym kodzie, gdzie obiekt jest znany być w pełni kompletny.

Niektóre przypadki do rozważenia:

  • Podklasa nadpisuje setNavigationController i odwołuje swoje Ivars przydzielone przez init. Awaria na init.
  • Zastępuje podklasę setNavigationController i odwołuje się do własnych znaków iv wypuszczonych w dealloc. Awaria na dealokatorze.
  • Zastępuje podklasy setNavigationController i odrysowuje niektóre części ekranu. Bezcelowe marnowanie cykli lub glitchy wyświetlania.
  • Inne obiekty są zwalniane jednocześnie obserwować navigationController i te obserwatorzy ogień podczas dealloc
  • itp
Powiązane problemy