ARC - Znaczenie __unsafe_unretained?

80

Chcę się tylko upewnić, że dobrze to zrobiłem:

  1. Czy potrzebuję __unsafe_unretainobiektów, których nie posiadam?
  2. Jeśli obiekt to __unsafe_unretainedCzy muszę użyć assignw @property? Czy to oznacza, że ​​przedmiot nie jest zachowany, a jedynie odnosi się do obiektu, do którego przypisuję?
  3. Kiedy chciałbym go używać, z wyjątkiem delegatów?
  4. Czy to rzecz ARC, czy była wcześniej używana?
shannoga
źródło

Odpowiedzi:

192

Kompilator LLVM 3.0 wprowadza cztery nowe kwalifikacyjne własności: __strong, __autoreleasing, __unsafe_unretained, i __weak. Pierwsze trzy są dostępne nawet poza ARC, zgodnie ze specyfikacją .

Jak wskazuje Joshua, domyślnie zakłada się, że wszystkie wskaźniki znajdują się __strongpod ARC. Oznacza to, że gdy obiekt jest przypisany do tego wskaźnika, jest on zachowywany tak długo, jak długo ten wskaźnik się do niego odnosi. Jest to dobre dla większości rzeczy, ale otwiera możliwość zachowania cykli, jak opisuję w mojej odpowiedzi tutaj . Na przykład, jeśli masz obiekt, który zawiera inny obiekt jako zmienną wystąpienia, ale ten drugi obiekt ma silne łącze z powrotem do pierwszego jako jego delegat, te dwa obiekty nigdy nie zostaną zwolnione.

Z tego powodu istnieją kwalifikatory __unsafe_unretainedi __weak. Najczęściej są używane w przypadku delegatów, w przypadku których należy zdefiniować właściwość dla tego delegata za pomocą atrybutu weaklub unsafe_unretained( assignjest to efektywne unsafe_unretained), a następnie dopasować ją, oznaczając odpowiednią zmienną wystąpienia za pomocą __weaklub __unsafe_unretained. Oznacza to, że zmienna wystąpienia delegata nadal będzie wskazywać z powrotem na pierwszy obiekt, ale nie spowoduje zachowania tego obiektu, przerywając w ten sposób cykl przechowywania i umożliwiając zwolnienie obu obiektów.

Poza delegatami jest to przydatne do przerwania wszelkich innych cykli przechowywania, które mogą powstać w kodzie. Narzędzie Leaks zawiera teraz widok Cykle, który przedstawia w sposób graficzny cykle zatrzymania wykryte w aplikacji.

Obie __unsafe_unretainedi __weakzapobiegają zatrzymywaniu obiektów, ale w nieco inny sposób. Ponieważ __weakwskaźnik do obiektu zostanie przekonwertowany nilna po cofnięciu alokacji obiektu, na który wskazuje, co jest bardzo bezpiecznym zachowaniem. Jak sama nazwa wskazuje, __unsafe_unretainedbędzie nadal wskazywać pamięć, w której znajdował się obiekt, nawet po zwolnieniu go. Może to prowadzić do awarii z powodu dostępu do tego zwolnionego obiektu.

Dlaczego miałbyś __unsafe_unretainedwtedy używać ? Niestety __weakjest obsługiwany tylko w systemach iOS 5.0 i Lion jako cele wdrożenia. Jeśli chcesz wrócić do iOS 4.0 i Snow Leopard, musisz użyć __unsafe_unretainedkwalifikatora lub użyć czegoś takiego jak MAZeroingWeakRef Mike'a Asha .

Brad Larson
źródło
2
I oczywiście __unsafe_unretainedmoże być przydatny do definiowania tablic C NSStringstałych i tym podobnych, np.NSString __unsafe_unretained *myStrings = { @"Foo", @"Bar", @"Baz", nil };
jlehr
2
@shannoga - Nie, musisz ręcznie określić __weakjako kwalifikator, aby używał tego rodzaju wskaźników. Nadal możesz używać __unsafe_unretainedz celem czysto 5.0 i nie będzie się tak zachowywać __weak. Jeśli potrzebujesz czegoś, co będzie przełączać się między tymi dwoma trybami w zależności od tego, czy twój cel go obsługuje, możesz użyć definicji specyficznej dla kompilatora, jak sugeruję tutaj: stackoverflow.com/a/8594878/19679
Brad Larson
4
@jlehr - NSString *myStrings = { @"Foo", @"Bar" };nie jest poprawną składnią celu-C; @"Foo"ma NSString*sam typ . Być może miałeś na myśli NSString *myStrings[] = { @"Foo", @"Bar" };, ale w tym przypadku nie bardzo rozumiem, jak __unsafe_unretainedbyłoby to szczególnie przydatne.
Quuxplusone,
2
@Quuxplusone W obu przypadkach - mieszałem tablice C ze strukturami. Powinienem był powiedzieć, że __unsafe_unretainedmogą to być przydatne elementy struct foo { __unsafe_unretained NSString * const s; int x; };
składowe
1
Ma również konsekwencje dla Class. Zobacz: stackoverflow.com/a/14245894/392847
Quintin Willison
4
  1. Nie, możesz również użyć weakdo obiektów, których nie jesteś właścicielem.
  2. Nie, możesz również użyć unsafe_unretainedna posesji.
  3. Rozumiem, że unsafe_unretainedprzedmioty są takie weaksame, bez dodatkowego bezpieczeństwa polegającego na usuwaniu ich, gdy przedmiot, na który wskazują, zostanie zwolniony (i związane z tym koszty ogólne).
  4. To jest całkowicie kwestia ARC.
Sergey Kalinichenko
źródło
Właściwie, co dziwne, unsafe_unretainediVars, gdy są ustawione w czasie wykonywania, zachowują się tak samo strong, jak jedynki, co prowadzi mnie do przekonania, że unsafe_unretainedjest to po prostu wskazówka kompilatora, podczas gdy słaby nie. Więcej informacji tutaj: stackoverflow.com/questions/11621028/…
Richard J. Ross III
4

__unsafe_unretainedjest identyczny z tym, co domyślne przechowywanie obiektu było przed ARC. W przypadku ARC wartość domyślna oznacza teraz, __strongże masz do niego odniesienie, dopóki nie wyjdzie ono poza zakres.

Joshua Weinberg
źródło
1

Kolejna uwaga dotycząca __unsafe_unretained: mam awarie w mojej aplikacji na urządzeniu, a NIE na symulatorze z iVars zadeklarowanym jako __unsafe_unretained! Tak, to był błąd w kodzie z migracji ARC, ale pierwszy raz zauważyłem taką różnicę między urządzeniem a symulatorem.

Gerd
źródło