Próbuję rozwiązać zagadkę.
__strong
jest wartością domyślną dla wszystkich zachowywalnych wskaźników obiektów Objective-C, takich jak NSObject, NSString itp. Jest to silne odniesienie. ARC równoważy to z a -release
na końcu zakresu.
__unsafe_unretained
równa się starej drodze. Służy do słabego wskaźnika bez zatrzymywania obiektu możliwego do zachowania.
__weak
jest podobna __unsafe_unretained
z tą różnicą, że jest to słabe odniesienie z automatycznym zerowaniem, co oznacza, że wskaźnik zostanie ustawiony na zero, gdy tylko obiekt, do którego się odwołuje, zostanie zwolniony. Eliminuje to niebezpieczeństwo zwisających wskaźników i błędów EXC_BAD_ACCESS.
Ale do czego dokładnie się __autoreleasing
przydaje? Trudno mi znaleźć praktyczne przykłady, kiedy muszę używać tego kwalifikatora. Uważam, że jest to tylko dla funkcji i metod, które oczekują wskaźnika-wskaźnika, takiego jak:
- (BOOL)save:(NSError**);
lub
NSError *error = nil;
[database save:&error];
które zgodnie z ARC należy zadeklarować w ten sposób:
- (BOOL)save:(NSError* __autoreleasing *);
Ale to jest zbyt niejasne i chciałbym w pełni zrozumieć, dlaczego . Fragmenty kodu, które znajduję, umieszczają __autoreleasing pomiędzy dwiema gwiazdkami, co dla mnie wygląda dziwnie. Typ to NSError**
(wskaźnik-wskaźnik do NSError), więc po co umieszczać je __autoreleasing
pomiędzy gwiazdami, a nie tylko przed nimi NSError**
?
Mogą też istnieć inne sytuacje, na których muszę polegać __autoreleasing
.
źródło
Odpowiedzi:
Masz rację. Jak wyjaśnia oficjalna dokumentacja:
Wszystko to jest bardzo dobrze wyjaśnione w przewodniku przejścia ARC .
W Twoim przykładzie NSError deklaracja oznacza
__strong
niejawnie:Zostanie przekształcony w:
Kiedy wywołujesz swoją
save
metodę:Kompilator będzie musiał wtedy utworzyć zmienną tymczasową ustawioną na
__autoreleasing
. Więc:Zostanie przekształcony w:
Możesz tego uniknąć, deklarując
__autoreleasing
bezpośrednio obiekt błędu jako .źródło
__autoreleasing
jest używany tylko dla argumentów przekazywanych przez odwołanie. Jest to szczególny przypadek, ponieważ masz wskaźnik do wskaźnika obiektu. Tak nie jest w przypadku takich rzeczy, jak wygodne konstruktory, ponieważ zwracają one tylko wskaźnik do obiektu, a ARC obsługuje go automatycznie.W związku z odpowiedzią Macmade i pytaniem uzupełniającym Dumnym członka w komentarzach (opublikowałby to również jako komentarz, ale przekracza maksymalną liczbę znaków):
Oto dlaczego kwalifikator zmiennej __autoreleasing jest umieszczony między dwiema gwiazdami.
Przedmowa, poprawna składnia deklarowania wskaźnika obiektu z kwalifikatorem to:
Kompilator to wybaczy:
ale to nie jest poprawne. Zobacz przewodnik przejścia na Apple ARC (przeczytaj sekcję rozpoczynającą się od „Powinieneś poprawnie dekorować zmienne ...”).
Aby odpowiedzieć na aktualne pytanie: Podwójny wskaźnik nie może mieć kwalifikatora zarządzania pamięcią ARC, ponieważ wskaźnik wskazujący na adres pamięci jest wskaźnikiem do typu pierwotnego, a nie wskaźnikiem do obiektu. Jednak gdy deklarujesz podwójny wskaźnik, ARC chce wiedzieć, jakie są zasady zarządzania pamięcią dla drugiego wskaźnika. Dlatego zmienne z podwójnym wskaźnikiem są określane jako:
Zatem w przypadku argumentu metody, który jest podwójnym wskaźnikiem NSError, typ danych jest deklarowany jako:
który w języku angielskim mówi „wskaźnik do __autoreleasing wskaźnika obiektu NSError”.
źródło
Ostateczna specyfikacja ARC mówi, że
Na przykład kod
faktycznie zostanie przekonwertowany na
... dlatego działa, gdy masz parametr
NSError* __autoreleasing * errorPointer
, wywołana metoda przypisze błąd do*errorPointer
i uruchomi się powyższa semantyka.Możesz użyć
__autoreleasing
w innym kontekście, aby zmusić obiekt ARC do puli autorelease, ale nie jest to zbyt użyteczne, ponieważ ARC wydaje się używać puli autorelease tylko podczas powrotu metody i już obsługuje to automatycznie.źródło