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ę __strong
pod 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_unretained
i __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 weak
lub unsafe_unretained
( assign
jest to efektywne unsafe_unretained
), a następnie dopasować ją, oznaczając odpowiednią zmienną wystąpienia za pomocą __weak
lub __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_unretained
i __weak
zapobiegają zatrzymywaniu obiektów, ale w nieco inny sposób. Ponieważ __weak
wskaźnik do obiektu zostanie przekonwertowany nil
na po cofnięciu alokacji obiektu, na który wskazuje, co jest bardzo bezpiecznym zachowaniem. Jak sama nazwa wskazuje, __unsafe_unretained
bę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_unretained
wtedy używać ? Niestety __weak
jest 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_unretained
kwalifikatora lub użyć czegoś takiego jak MAZeroingWeakRef Mike'a Asha .
__unsafe_unretained
może być przydatny do definiowania tablic CNSString
stałych i tym podobnych, np.NSString __unsafe_unretained *myStrings = { @"Foo", @"Bar", @"Baz", nil };
__weak
jako kwalifikator, aby używał tego rodzaju wskaźników. Nadal możesz używać__unsafe_unretained
z 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/19679NSString *myStrings = { @"Foo", @"Bar" };
nie jest poprawną składnią celu-C;@"Foo"
maNSString*
sam typ . Być może miałeś na myśliNSString *myStrings[] = { @"Foo", @"Bar" };
, ale w tym przypadku nie bardzo rozumiem, jak__unsafe_unretained
byłoby to szczególnie przydatne.__unsafe_unretained
mogą to być przydatne elementystruct foo { __unsafe_unretained NSString * const s; int x; };
Class
. Zobacz: stackoverflow.com/a/14245894/392847weak
do obiektów, których nie jesteś właścicielem.unsafe_unretained
na posesji.unsafe_unretained
przedmioty są takieweak
same, 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).źródło
unsafe_unretained
iVars, gdy są ustawione w czasie wykonywania, zachowują się tak samostrong
, jak jedynki, co prowadzi mnie do przekonania, żeunsafe_unretained
jest to po prostu wskazówka kompilatora, podczas gdy słaby nie. Więcej informacji tutaj: stackoverflow.com/questions/11621028/…__unsafe_unretained
jest 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.źródło
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.
źródło