Dlaczego delegaci Objective-C zazwyczaj otrzymują przypisanie własności zamiast zachowywania?
Przeglądam wspaniały blog prowadzony przez Scotta Stevensona i staram się zrozumieć fundamentalną koncepcję Objective-C przypisywania delegatom własności "przypisać" vs "zachować". Zauważ, że oba są takie same w środowisku śmieci. Głównie zajmuję się środowiskiem opartym na GC (np.
Prosto z bloga Scotta:
" słowo kluczowe assign wygeneruje setter, który przypisuje wartość zmiennej instancji bezpośrednio, a nie kopiowanie lub zachowywanie go. Jest to najlepsze dla prymitywnych typów, takich jak NSInteger i CGFloat, lub obiektów, których bezpośrednio nie posiadasz, takich jak delegaty."
Co to znaczy, że nie posiadasz bezpośrednio obiektu delegata? Zazwyczaj Zatrzymuję swoich delegatów, ponieważ jeśli nie chcę, aby odeszli w otchłań, zachowam to za mnie. Zwykle abstrakcyjny UITableViewController z dala od odpowiedniego źródła danych i delegata również. Zatrzymuję również ten konkretny przedmiot. Chcę zrobić jasne, że nigdy nie odchodzi, więc mój UITableView zawsze ma swojego delegata w pobliżu.
Może ktoś jeszcze wyjaśnić gdzie/dlaczego się mylę, żebym mógł zrozumieć ten wspólny paradygmat programowania Objective-C 2.0 polegający na używaniu właściwości assign na delegatach zamiast zachowywania?
Dzięki!
4 answers
Powodem, dla którego unikasz zatrzymywania delegatów, jest to, że musisz unikać cyklu zatrzymywania:
A tworzy B A ustawia się jako delegat B … A jest zwolniony przez jego właściciela
Gdyby B zachował A, A nie zostałby zwolniony, ponieważ B posiada a, więc dealloc A nigdy nie zostałby wywołany, powodując wyciek ZARÓWNO A, jak i B .
Nie powinieneś martwić się o odejście A, ponieważ posiada B i tym samym pozbawia się go w dealloc.
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
2015-05-10 22:25:00
Ponieważ obiekt wysyłający wiadomości delegata nie jest jego właścicielem.
Wiele razy jest odwrotnie, jak w przypadku, gdy kontroler ustawia się jako delegat widoku lub okna: kontroler jest właścicielem widoku / okna, więc jeśli Widok / okno posiada swojego delegata, oba obiekty byłyby właścicielami siebie nawzajem. Jest to oczywiście cykl zachowawczy, podobny do wycieku z tą samą konsekwencją (obiekty, które powinny być martwe, pozostają żywe).
Innym razem, obiekty są rówieśnikami: żaden z nich nie jest właścicielem drugiego, prawdopodobnie dlatego, że oba są własnością tego samego trzeciego obiektu.
Tak czy inaczej, obiekt z delegatem nie powinien zachować swojego delegata.
(jest przynajmniej jeden wyjątek, nawiasem mówiąc. Nie pamiętam, co to było i nie sądzę, żeby był ku temu dobry powód.)
Dodatek (dodano 2012-05-19): w polu ARC należy użyć weak
zamiast assign
. Słabe odwołania są ustawiane na nil
automatycznie, gdy obiekt umiera, wyeliminowanie możliwości, że obiekt delegujący będzie wysyłać wiadomości do martwego delegata.
Jeśli z jakiegoś powodu trzymasz się z dala od ARC, Zmień przynajmniej właściwości assign
, które wskazują na obiekty na unsafe_unretained
, które wyraźnie wskazują, że jest to nieuregulowane, ale nie zerujące odniesienie do obiektu.
assign
pozostaje odpowiedni dla wartości innych niż obiekt zarówno pod ARC, jak i MRC.
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-05-19 09:04:07
Zauważ, że gdy masz przypisanego delegata, bardzo ważne jest, aby zawsze ustawiać wartość tego delegata na nil, gdy obiekt ma być deallocowany - więc obiekt powinien zawsze uważać, aby nie usuwać odwołań do delegatów w dealloc, jeśli nie zrobił tego gdzie indziej.
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
2009-05-28 15:17:46
Jednym z powodów tego jest unikanie zatrzymywania cykli. Aby uniknąć sytuacji, w której A i B oba obiekty odwołują się do siebie i żaden z nich nie jest zwolniony z pamięci.
Acutally assign jest najlepszy dla prymitywnych typów, takich jak NSInteger i CGFloat, lub obiektów, których bezpośrednio nie posiadasz, takich jak delegaty.
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
2015-12-28 10:01:51