2012-02-09 19 views
35

Mam UIViewController, który jest pchany na kontroler kontenera, a następnie wyskoczył, a przy użyciu przydziału instrumentu, widzę, że kontroler widoku jest następnie niszczony. Jednak punkt przerwania dealloc kontrolera nigdy nie zostanie osiągnięty. Czy ktoś wie, dlaczego nie nazywa się dealloc? Czy ARC może zniszczyć obiekt bez wywoływania dealloc?Dealloc nie jest wywoływany na aplikacji ARC

Co więcej, wyłączyłem NSZombies (niektórzy twierdzą, że może spowodować, że debugowanie nie rozpocznie się).

Edit:

dealloc nie robi wiele, po prostu drukuje na konsoli, a to nigdy nie jest wywoływana:

- (void)dealloc { NSLog(@"Deallocating..."); }

nie mogę pisać kontroler-to pojemnik jest zastrzeżony i zbyt skomplikowany. Dealloc jest nazywany konsekwentnie na niektórych kontrolerach, a nie na innych. Jeśli uda mi się znaleźć czas, postaram się opublikować uproszczoną wersję, która powiela problem.

Czy istnieje sposób sprawdzenia, czy NSZombies jest wyłączony?

Edit2

jestem delegowania zrzut ekranu z instrumentów; Wydaje mi się, że prawidłowo rozdziela.

enter image description here

+1

To powinien być nazywany zaczyna, nawet w ARC. Nie możesz uwzględnić [super dealera], ale ARC doda to za Ciebie. Może udostępnić kod tej klasy? – picciano

+0

Czy istnieją metody w metodzie dealloc? – zaph

+1

Powinieneś opublikować kod '- (void) dealloc {}'. – NJones

Odpowiedz

19

Jeśli dealloc nie jest wywoływana przez VC, to chciałbym postawić tam jest okrągły odniesienie gdzieś w kodzie, który jest zapobiegając łuk z wywołaniem dealloc.

Niektóre rzeczy do sprawdzenia:

  1. Czy masz obiekt instancji, że odniesienia powrotem do VC?
  2. Jeśli chcesz odwołać się do VC, upewnij się, że użyłeś atrybutu "__unsafe_unretained" lub "weak" (iOS5 +), aby cykl zatrzymania nie wystąpił.

Zostałem przyciśnięty w tyłek, gdy moje deklaracje delegatów nie korzystały z __unsafe_unretained.

88

Właśnie natknąłem podobnego problemu. Czy masz jakieś bloki, w których odnosisz się do "ja"? Miałem kilka bloków do obserwacji powiadomień w moim init, gdzie miałem na myśli "self". Pod ARC self jest zatrzymywany w blokach. Mój dealloc nie został wezwany i właśnie wtedy usunąłem obserwację.

Sztuką jest utworzenie odwołania __weak (iOS 5+) lub __unsafe_unretained (iOS 4.x) do swojego "ja" i użycie go do uzyskania dostępu do siebie lub dowolnego _iVars (spowoduje to zatrzymanie "ja" jako dobrze) w bloku. Oto przykład.

__unsafe_unretained TableViewController *weakSelf = self; 
[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) { 
     if (weakSelf.tableView) { 
      [weakSelf.tableView reloadData]; 
     } 
    }]; 
+0

Po przejrzeniu przez kod wielu migrujących kodów (od projektów innych niż łukowe do projektów łukowych) mogę potwierdzić, że jest to główne źródło niepożądanego zatrzymania -cycles. W końcu: blok przydaje się i jest łatwo stworzony, prawda! – leviathan

+0

Nie wyrejestrowując obserwatora, oznacza to, że będzie strzelał w odpowiedzi na powiadomienie * na zawsze *, nawet po tym, jak "ja" już dawno zniknęło. A jeśli dodasz tego obserwatora wiele razy, to za każdym razem, gdy to powiadomienie się wydarzy, będzie strzelać do wielu bezużytecznych obserwatorów, na zawsze. To nie może być dobra praktyka programowania. – user102008

+7

Dla uproszczenia możemy użyć '__weak typeof (self) weakSelf = self;' – Vive

16

Nawet z ARC można sprawdzić liczbę odwołań ręcznie:

CFIndex rc = CFGetRetainCount((__bridge CFTypeRef)myObj); 

można wiedzieć na pewno, jeśli kod jest zawieszony w cyklu pamięci.

+0

Zgadzam się z @Dean Liu - Instrumenty nieporozumienie, podejrzewam, że nie jest zwolnienie z powodu cyklu pamięci. Czasami dostaję się do pułapek przy użyciu bloków - zwłaszcza jeśli blok odnosi się do "ja", jest to bardzo łatwe do zrobienia. – jbbenni

+0

dziękuję, to jest bardzo pomocne! –

+3

Pomogło! (Na pewno byłoby dobrze, gdyby istniała odpowiednia metoda wywołania funkcji, która dała listę wszystkich obiektów, które odwoływały się do obiektu). –

9

Oto kolejna wskazówka (zdarzyło mi):

tl; dr: spojrzeć na swoje zmiennych instancji klasy, jak również, nie tylko właściwości klasy. Czy przydzielasz dowolną zmienną instancji w kodzie, a później nie ustawiasz jej później na nil?

Posiadałem klasę z paczką właściwości (@property (nonatomic, strong) i @property (nonatomic, weak)) w jej pliku nagłówkowym. Wyjaśniłem te właściwości jeden po drugim, aby zobaczyć, czy to coś zmieni. To nie mialo miejsca. Główna klasa wciąż nie została zwolniona. Więc problemu nie było w nieruchomościach.

Po tym, co zrobiłem, przyjrzałem się zmiennym instancji. Miałem jedną zmienną instancji (która była UIViewController), którą utworzyłem na viewDidLoad. Ten jeden nigdy został zwolniony!

Kiedy usunąłem tę zmienną, na pewno moja główna klasa nazywa się dealloc.

Ponieważ ten nie został zwolniony, moja główna klasa również nie została zwolniona. Przeniesienie tej instancji zmiennej jako właściwości rozwiązało problem dla mnie.

Pytanie: Nie jestem pewien, dlaczego tak się dzieje. Czy system operacyjny ma lepszą kontrolę nad właściwościami klasy niż zmiennymi instancji? Wydaje się nieco dziwne, że klasa nadrzędna, która zawiera zmienną instancji, nie zostaje zwolniona z powodu swojej zmiennej instancji.

21

W moim przypadku był to NSTimer. Zachowuje swój cel, więc musisz unieważnić timer, gdy skończysz z kontrolerem widoku.

13

Moim problemem byli delegaci.

Sprawdź swoich delegatów! Nieruchomość delegat powinien mieć weak określone: ​​

@property (weak, nonatomic) id<SomeProtocol> delegate;

Powiązane problemy