2009-05-26 9 views
29

poprawny przykład:Dlaczego muszę wywoływać super-wstępne alokacje na końcu, a nie pierwsze?

- (void)dealloc { 
    [viewController release]; 
    [window release]; 
    [super dealloc]; 
} 

źle przykład:

- (void)dealloc { 
    [super dealloc]; 
    [viewController release]; 
    [window release]; 
} 

Althoug w alsmost wszystkich innych przypadkach, gdy przesłanianie metody Chciałbym najpierw zadzwonić do wdrożenia metody super jest, w tym przypadku jabłka zawsze wywołuje [SUPER dealloc ] na końcu. Czemu?

Odpowiedz

54

To tylko wytyczna. Możesz zadzwonić po inne instrukcje po [super dealloc]. jednak nie można już uzyskać dostępu do zmiennych nadklasy, ponieważ są one zwalniane po wywołaniu [super dealloc]. Zawsze można bezpiecznie wywołać superklasę w ostatniej linii.

Również klucze KVO i zależne (wyzwalane) mogą wywoływać efekty uboczne, jeśli są zależne od już zwolnionych zmiennych składowych.

+5

W ARC, nie musisz w ogóle wywoływać '[super dealall]', powoduje to błąd kompilatora. – teradyl

12

Nie wiem nic o programowaniu dla iPhone'a, ale zakładam, że to z tego samego powodu, że destruktory muszą być wywoływane w odwrotnej kolejności. Chcesz się upewnić, że wszystkie twoje "śmieci" zostaną oczyszczone przed wywołaniem twojej nadklasy. Jeśli zrobisz to na odwrót, rzeczy mogą stać się bałaganiarskie. Na przykład, jeśli destruktor musi uzyskać dostęp do pamięci, że super destructor został już uwolniony:

class X { 
    private Map foo; 

    function __construct() { 
     foo = new Map(); 
    } 

    function __destruct() { 
     foo.free; 
    } 
} 

class Y extends X { 
    function __construct() { 
     super.__construct(); 
     map.put("foo", 42); 
    } 

    function __destruct() { 
     super.__destruct(); 
     if (map.containsKey("foo")) { // boooooooooom! 
      doSomething(); 
     } 
    } 
} 

Nie możesz napotkać ten problem w kodzie, ponieważ „wiesz co robisz”, ale jest bezpieczniejszą i ogólnie lepszą praktyką, aby nie robić takich rzeczy.

+1

Czy ktoś chce wyjaśnić, dlaczego zostało to odrzucone? – n3rd

+4

Czy ktoś chce wyjaśnić, dlaczego zostało ono wznowione? –

+0

Zgaduję, że przynajmniej częściowo odpowiedział na to pytanie. Z drugiej strony z drugiej strony wynika, że ​​odpowiedź była niepomocna lub po prostu błędna. Gdyby było źle, bardzo chciałbym wiedzieć, dlaczego mogę się nauczyć z mojego błędu. A może po prostu polemizujesz? – n3rd

5

[super dealloc] zwalnia pamięć używaną przez obiekt, w tym wskaźniki do viewController i okna. Odwoływanie się do zmiennych po ich uwolnieniu jest w najlepszym wypadku niebezpieczne.

Zobacz this answer.

1

Praktycznie prawie na końcu masz [super dealloc], ponieważ uwalnia on zmienne nadklasy i nie można już uzyskać do nich dostępu.

Jeden wyjątek dotyczy podklasy UITableViewController, która używa innej klasy jako delegata widoku tabeli. W takim przypadku musisz zwolnić delegata widoku tabeli po [super dealloc], ponieważ widok tabeli odwołuje się do delegata widoku tabeli, a widok tabeli musi zostać najpierw zwolniony.

+1

Czy możesz podać trochę więcej szczegółów swojego wyjątku? Brzmi dla mnie trochę źle. –

+1

@ Mark: też jest mi źle. Zwykle nie zachowałbyś nawet delegata na pierwszym miejscu, aby uniknąć zatrzymywania cykli. –

2

Oto prawdziwy przykład, gdzie [super dealok] musi być ostatni, w przeciwnym razie wywołanie removeFromRunLoop spowoduje awarię. Nie jestem pewien, co dzieje się wewnątrz removeFromRoLoop NSOutputStream, ale wydaje się, że w tym przypadku uzyskuje dostęp do "self".

Setup:

[outputStream setDelegate:self]; 
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 

dealloc:

- (void)dealloc { 
    if (outputStream) { 
     [outputStream close]; 
     [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] 
           forMode:NSDefaultRunLoopMode]; 
     [outputStream release]; 
     outputStream = nil; 
    } 
    delegate = nil; 
    [super dealloc]; // must be last! 
} 
1

[do ostatniego postu] Czy nie tableview odwołującego delegata jest odpowiedzialny za emisję własną delegat? Wydaje mi się, że zachował ją, gdy był ustawiony (abyś mógł go zwolnić lub samozwaszyć) i sam się o to zatroszczył?

Jeśli chodzi o pytanie OP, zawsze będę dzwonił super pierwszy, jeśli będę konstruował i dzwoni super super, jeśli ulegam destrukcji.Myślę o tym, że "chcę super zbudować to, co chce, więc mogę na tym oprzeć i chcę, żeby super zburzyło się po tym, jak posprzątam po sobie". Praktycznie wszystkie wywołania, z których korzystam, są konstruowane, z wyjątkiem dealloc, dlatego zawsze będziesz je widział w moim kodzie dealloc.

Powiązane problemy