2009-04-30 10 views
7

Gdzieś czytałem, że - w zakresie niskich ostrzeżenia pamięci i zrezygnowania z niewidoczną widok z wszystkich jego subviews (= cała stalówka, jak sądzę), należy to zrobić:Dlaczego powinienem napisać [anView release], anView = nil; zamiast [wydanie anView] ;?

-(void)dealloc { 
    [anView release], anView = nil; 
    [someImageView release], someImageView = nil; 

    [super dealloc]; 
} 

zamiast

-(void)dealloc { 
    [anView release]; 
    [someImageView release]; 

    [super dealloc]; 
} 

Jaki jest powód, dla którego uziemienie tych wskaźników jest zerowe (= "brak obiektu"), po wywołaniu wersji? Niech zgadnę: jakaś inna metoda mogłaby -retainować widok z jakiegoś powodu (ktokolwiek na przykład, kiedy to może się zdarzyć?), Wtedy zdarzyło się coś, co zrobiłeśReceiveMemoryWarning, i zwolnisz cały widok nib +, który obecnie nie jest widoczny (np. w aplikacji multiview). Jak tylko użytkownik chce ponownie zobaczyć ten widok, szybko załadowałbyś stalówkę ponownie, a następnie: Ładuje wszystkie widoki, łączy wyjścia i BANG! Twój drugi widok jest teraz zawieszony bez wskaźnika gdzieś samotny w cegle pamięci, powodując tłusty i głęboki wyciek pamięci, aż do awarii aplikacji.

Dobrze/źle?

Odpowiedz

1

zamiast robić uwolnienie expicit i ustawione na zero, jeśli Akcesory mają właściwości związane z nimi YOC i wykonaj następujące czynności jako bardziej zwięzły sposób:

- (void) dealloc 
{ 
    self.retainedProperty1 = nil; 
    self.retainedProperty2 = nil; 
    self.copiedProperty = nil; 
    self.assignedProperty = nil; 
} 

ten sposób można mieć kod, który ma mniej powtórzenie, ponieważ zsyntetyzowany kod zajmie się Twoimi wydaniami.

Edycja: powinienem wskazać, że twoje właściwości nie mogą być odczytane tylko w trybie gotowości lub w innych przypadkach pojawią się błędy kompilatora z oczywistych powodów :)

+5

Nie. Jest to * wyraźnie zabronione * przez firmę Apple i jest dobrym sposobem na spowodowanie awarii w pewnych okolicznościach. Zobacz http://stackoverflow.com/questions/192721/why-shouldnt-i-use-obective-c-2-0-accessors-in-init-dealloc –

+0

To połączenie ma dobry punkt, ale czy nadal jest zły pomysł, jeśli używasz go tylko do właściwości Readwrite, które są w pełni syntetyzowane? (co oznacza, że ​​nie deklarujesz syntezowania dla właściwości i wciąż przesłonię gettera lub ustawiacza). – Kevlar

+0

To prawdopodobnie dobrze, na razie, z w pełni zsyntetyzowanymi właściwościami. Ale Apple nie gwarantuje, że jest to dozwolone i nie zaleca tego, więc może to pęknąć w dowolnym przyszłym pakiecie SDK. –

14

Zasada jest bardziej ogólna niż UIView. w rzeczywistości jest bardziej ogólny niż metoda Objective-C/Cocoa -release. Obowiązuje również z funkcjami pamięciowymi C malloc()/free().

Gdy nie potrzebujesz już przedmiotu lub strefy pamięci, najpierw ją zwolnij/zwolnij. Następnie, aby upewnić się, że nie użyjesz go ponownie, wyczyścisz środki dostępu do tego obiektu lub strefy pamięci przez przypisanie obiektu nil do obiektu lub NULL do wskaźnika pamięci.

+4

+1. Główną kwestią jest to, że wyłuskiwanie pustego wskaźnika powoduje natychmiastowe przerwanie wykonywania, podczas gdy odwracanie wskaźnika do już uwolnionej pamięci może "działać" przez jakiś czas i prowadzić do nieprzyjemnych błędów. – zoul

+0

Dzięki. Zastanawiam się, dlaczego tak rzadko widzimy ten wzór w przykładach kodu. Nigdy nie widziałem tego w kodzie Apple'a. Ale brzmi to dla mnie rozsądnie i myślę, że i tak nie będzie bolało. – Thanks

+0

Przykładowy kod rzadko stosuje sprawdzone metody. celem większości kodu przykładowego jest wykazanie zasady, api lub metody tak zwięźle jak to tylko możliwe. – m4rkk

11

Some other method could have -retain'ed the view for some reason

Jeśli nie jesteś powołując dealloc siebie, nazywa się tylko wtedy, gdy licznik zachowuje się zero.

Należy zauważyć, że w Objective-C wysłanie wiadomości do obiektu "nil" jest (często) całkowicie w porządku. Spowoduje to, że nie spowoduje zatrzymanie programu, ale wiadomość zostanie po prostu zignorowana. Jednak nie można wysłać wiadomości do zwolnionego obiektu, co może spowodować awarię.

Więc dodaje nie daje błąd:

[anView release]; 
[anView doSomething]; 

Ale to jest w rzeczywistości OK:

[anView release]; 
anView = nil; 
[anView doSomething]; 

to kwestia gustu, ale na powyższe, to polubisz w Faktycznie woli awarię programu, zamiast zastanawiać się, dlaczego coś nie jest wykonywane ...

Zobacz także Sending Messages to nil z Apple Introduction to The Objective-C 2.0 Programming Language.

2

Używam tego wzoru dużo:

- (void) showHelp: (id) sender 
{ 
    if (helpController == nil) 
    { 
     helpController = [[HelpController alloc] initWithNibName: @"Help" bundle: [NSBundle mainBundle]]; 
    } 
    [self presentModalViewController: helpController animated: YES];  
} 
- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview 
    // Release anything that's not essential, such as cached data 
    [helpController release]; 
    helpController = nil; 
} 

prawie wszędzie, że przydzieli viewcontroller który jest modalne, lub inaczej „tymczasowy”. W ten sposób zawiesza się, jeśli potrzebuję go ponownie, ale znika, gdy pamięć się wyczerpuje.

4

Metoda -dealloc jest wywoływana, gdy obiekt zostanie zwolniony i żadne inne metody na obiekcie nie zostaną wykonane później. Dlatego ustawienie dowolnej zmiennej instancji na zero nie ma wpływu poza tym obiektem.

Jeśli zwalniałeś obiekt (bez użycia settera) gdzieś indziej w klasie, ważne byłoby ustawienie zmiennej instancji na zero, aby kod nigdzie indziej nie wysyłał wiadomości na ten adres.

+1

"żadne inne metody na obiekcie nie zostaną wykonane po" - +1 dla tego jasnego wyjaśnienia oczywistości. Dzięki! (Jeśli chodzi o "ważne ustawienie zmiennej instancji na zero, aby uniemożliwić kodowi w innym miejscu wysyłanie wiadomości na ten adres", zastanawiam się, dlaczego ignorowanie niezamierzonej wiadomości jest preferowane przed otrzymaniem komunikatu o błędzie ...) – Arjan

+3

Ponieważ wszystkie programy zawierają błędy - nawet dobrze przetestowane, udostępnione klientowi. Rodzaje błędów generowanych przez wysyłanie wiadomości do zera (w zasadzie no-op) są zwykle mniej poważne niż błędy generowane przez wysłanie wiadomości do uwolnionego obiektu. Te pierwsze zwykle powodują błędy logiczne, gdy program nie działa dokładnie zgodnie z zamierzeniami, a drugi spowoduje awarię. Podczas programowania awarie są mile widziane, ponieważ pozwalają na odnalezienie błędu - nie w przypadku wydanych produktów. – m4rkk