UIViewController zapobiega rozładowaniu widoku

Gdy moja aplikacja na iPhone ' a otrzyma ostrzeżenie o pamięci, widoki Uiviewcontrollerów, które nie są obecnie widoczne, zostaną rozładowane. W jednym sterowniku rozładowanie widoku i wylotów jest raczej fatalne.

Szukam sposobu, aby zapobiec rozładowaniu tego widoku. Uważam to zachowanie za dość głupie - mam mechanizm cache, więc gdy pojawia się ostrzeżenie o pamięci-rozładowuję sobie Tony danych i uwalniam wystarczająco dużo pamięci, ale zdecydowanie potrzebuję tego widoku nietkniętego.

Widzę UIViewController posiada metodę unloadViewIfReloadable, która jest wywoływana, gdy pojawi się ostrzeżenie o pamięci. Czy ktoś wie jak powiedzieć Cocoa Touch, że mój widok nie jest doładowywany?

Jakieś inne sugestie, jak zapobiec rozładowaniu mojego widoku na ostrzeżeniu pamięci?

Z góry dzięki


Apple docs o cyklu życia widoku kontrolera widoku mówi:

DidReceiveMemoryWarning-domyślne implementacja zwalnia tylko widok jeśli stwierdzi, że jest bezpieczne do zrobienia więc

Teraz ... Nadpisuję didReceiveMemoryWarning pustą funkcją, która wywołuje NSLog, aby dać mi znać, że otrzymano Ostrzeżenie. Jednak-widok i tak się rozładowuje. Plus, na jakich kryteriach dokładnie decyduje, czy widok jest bezpieczny do rozładowania ... oh ! tyle pytań!
Author: Marin Todorov, 2010-06-03

5 answers

To, co wydaje mi się działać, to nadpisać setView:, Aby zignorować ustawienie na nil. To jest kludgy, ale to jest kludgy problem, i to załatwiło sprawę: {]}

-(void)setView:(UIView*)view {
    if(view != nil || self.okayToUnloadView) {
        [super setView:view];
    }
}
 13
Author: umop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-24 07:32:04

Zgodnie z dokumentami, Domyślna implementacja didReceiveMemoryWarning: uwalnia Widok, jeśli jest to bezpieczne (np.: superview= = nil).

Aby zapobiec zwolnieniu widoku, możesz nadpisać didReceiveMemoryWarning: ale w swojej implementacji nie wywołaj [super didReceiveMemoryWarning]. Tam widok jest domyślnie zwalniany (jeśli nie jest widoczny).

Domyślna funkcja didReceiveMemoryWarning zwalnia widok przez wywołanie [viewcontroller setView:nil], więc można ją zastąpić.

 15
Author: progrmr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-03 14:08:55

Czy to może być takie proste?

Mimo że nigdzie w dokumentacji nie jest to wspomniane, wydaje się, że jeśli zachowam wyłącznie mój widok w viewDidLoad, to nie zostanie on zwolniony z ostrzeżeniem o pamięci. Próbowałem z kilku kolejnych ostrzeżeń w symulatorze i wszystkie nadal wydają się dobre.

Więc ... sztuczka na razie polega na "zatrzymaniu" w viewDidLoad, a zwolnieniu w dealloc - w ten sposób viewcontroller jest "zablokowany" z widokiem do czasu, kiedy musi być zwolniony.

Przetestuję jeszcze trochę i napiszę o wynikach

 1
Author: Marin Todorov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-03 12:30:44

Myślę, że żaden z tych pomysłów nie działa. Próbowałem nadpisać [didReceiveMemoryWarning], i to działało w niektórych telefonach, ale znalazłem jeden telefon rozładowany widok, zanim ta metoda została nawet wywołana(musiał być w bardzo niskiej pamięci lub coś). Overriding [setView] generuje mnóstwo ostrzeżeń dzienników, więc nie ryzykowałbym tego przez Apple. Zachowanie widoku spowoduje wyciek tego widoku-zapobiegnie awariom, ale naprawdę nie działa - Widok zostanie zastąpiony następnym razem, gdy interfejs sterowników jest załadowany.

Więc naprawdę musisz tylko zaplanować, że Twoje poglądy będą rozładowywane za każdym razem, gdy będą poza ekranem, co nie jest idealne, ale proszę bardzo. Najlepsze wzorce, które znalazłem do pracy z tym są natychmiastowe commit, więc twój interfejs jest zawsze aktualny, lub copy-edit-copy, gdzie kopiujesz swój model do tymczasowej instancji, wypełniasz swoje widoki i używasz natychmiastowego commit z tą instancją, a następnie skopiuj zmiany z powrotem do oryginalnego modelu, gdy użytkownik naciśnie "Zapisz" lub cokolwiek innego.

 1
Author: kingrichardthethird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-17 11:07:12

Ponieważ przyjęte rozwiązanie ma problemy z wywołaniem viewDidUnload, mimo że Widok został zablokowany przed wyczyszczeniem, używam innego, choć wciąż delikatnego podejścia. System rozładowuje Widok za pomocą wiadomości unloadViewForced: do kontrolera, więc przechwytuję ją, aby zablokować wiadomość. Zapobiega to błędnemu wywołaniu viewDidUnload. Oto kod:

@interface UIViewController (Private)
- (void)unloadViewForced:(BOOL)forced;
@end

- (void)unloadViewForced:(BOOL)forced {
    if (!_safeToUnloadView) {
        return;
    }
    [super unloadViewForced:forced];
}

To ma oczywiste problemy, ponieważ przechwytuje nieudokumentowaną wiadomość w UIViewController.

Progrmr zamieścił odpowiedź powyżej, która zaleca przechwytywanie didReceiveMemoryWarning zamiast. Na podstawie śladów stosu, które widziałem, przechwycenie tego też powinno zadziałać. Nie próbowałem tej trasy, ponieważ obawiam się, że może być inne czyszczenie pamięci, które również byłoby zablokowane (na przykład spowodowanie, że nie wywołuje kontrolerów widoku potomnego z komunikatem ostrzegawczym o pamięci).

 1
Author: John Stephen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-03 10:19:49