Przeglądam wspaniały blog prowadzony przez Scotta Stevensona i próbuję zrozumieć podstawową koncepcję Objective-C polegającą na przypisywaniu delegatom właściwości „przypisuj” zamiast „zachowaj”. Uwaga: oba są takie same w środowisku zbierania elementów bezużytecznych. Najbardziej interesuje mnie środowisko nie oparte na GC (np .: iPhone).
Bezpośrednio z bloga Scotta:
„Słowo kluczowe assign wygeneruje metodę ustawiającą, która bezpośrednio przypisuje wartość do zmiennej instancji, zamiast ją kopiować lub zachowywać. Jest to najlepsze dla typów pierwotnych, takich jak NSInteger i CGFloat, lub obiektów, których bezpośrednio nie posiadasz, takich jak delegaci”.
Co to znaczy, że nie jesteś bezpośrednio właścicielem obiektu delegata? Zwykle zatrzymuję swoich delegatów, ponieważ jeśli nie chcę, aby odeszli w otchłań, zatrzymanie zajmie się tym za mnie. Zwykle abstrakcyjne UITableViewController z dala od odpowiedniego źródła danych i deleguj również. Zachowuję również ten konkretny przedmiot. Chcę mieć pewność, że nigdy nie zniknie, więc mój UITableView zawsze ma swojego delegata.
Czy ktoś może dalej wyjaśnić, gdzie / dlaczego się mylę, aby zrozumieć ten wspólny paradygmat w programowaniu Objective-C 2.0 polegający na używaniu właściwości assign na delegatach zamiast zachowania?
Dzięki!
źródło
Odpowiedzi:
Powodem, dla którego unikasz zatrzymywania delegatów, jest to, że musisz unikać cyklu przechowywania:
A tworzy B A ustawia się jako delegat B… A zostaje zwolniony przez swojego właściciela
Gdyby B zatrzymał A, A nie zostałby zwolniony, ponieważ B jest właścicielem A, więc dealloc A nigdy nie zostałby sprawdzony, powodując zarówno A, jak i B. wyciek
Nie powinieneś się martwić, że A odejdzie, ponieważ jest właścicielem B i tym samym pozbywa się go w trybie dealloc.
źródło
weak
robi? Pytanie brzmi, dlaczego używaćassign
zamiastweak
?assign
zamiastretain
. Pytanie jest starsze niż ARC;weak
astrong
(to ostatnie jest synonimemretain
) nie istniało do czasu wprowadzenia ARC. Pytanie dotycząceweak
vs. należy zadaćassign
osobno.Ponieważ obiekt wysyłający komunikaty pełnomocnika nie jest właścicielem pełnomocnika.
Wiele razy dzieje się odwrotnie, tak jak gdy kontroler ustawia się jako delegat widoku lub okna: kontroler jest właścicielem widoku / okna, więc jeśli widok / okno jest właścicielem swojego delegata, oba obiekty byłyby właścicielami siebie nawzajem. Jest to oczywiście cykl zatrzymywania, podobny do wycieku z taką samą konsekwencją (obiekty, które powinny być martwe, pozostają żywe).
Innym razem obiekty są równorzędne: żaden z nich nie jest właścicielem drugiego, prawdopodobnie dlatego, że oba należą do tego samego trzeciego obiektu.
Tak czy inaczej, obiekt z delegatem nie powinien zachowywać swojego delegata.
(Nawiasem mówiąc, jest co najmniej jeden wyjątek. Nie pamiętam, co to było i nie sądzę, by istniał dobry powód).
Dodatek (dodano 19.05.2012): W ARC należy używać
weak
zamiastassign
. Ustawiane są słabe referencjenil
automatycznie, gdy obiekt umiera, co eliminuje możliwość, że delegujący obiekt zakończy wysyłanie wiadomości do martwego delegata.Jeśli z jakiegoś powodu trzymasz się z dala od ARC, przynajmniej zmień
assign
właściwości, które wskazują na obiektyunsafe_unretained
, które wyraźnie wskazują, że jest to niezerowe, ale niezerowe odniesienie do obiektu.assign
pozostaje odpowiedni dla wartości niebędących przedmiotem zarówno w ramach ARC, jak i MRC.źródło
NSURLConnection
zachowuje swojego delegata.weak
, ale to nie odpowiada na pierwotne pytanie: dlaczego Apple używaassign
zamiastweak
?assign
a nie zachowywane ”;weak
nie istniało, kiedy o to pytano. Twoje pytanie jest inne, które powinieneś zadać osobno. Chętnie na nie odpowiem.Zwróć uwagę, że gdy masz delegata, który jest przypisany, bardzo ważne jest, aby zawsze ustawiać tę wartość delegata na zero, gdy obiekt ma zostać zwolniony - więc obiekt powinien zawsze uważać, aby zerować odwołania delegata w dealloc, jeśli tak nie jest zrobiono to gdzie indziej.
źródło
Jednym z powodów jest unikanie zachowania cykli. Żeby uniknąć scenariusza, w którym obiekty A i B odwołują się do siebie i żaden z nich nie jest uwalniany z pamięci.
W rzeczywistości przypisywanie jest najlepsze dla typów pierwotnych, takich jak NSInteger i CGFloat, lub obiektów, których bezpośrednio nie posiadasz, takich jak delegaci.
źródło