ARC i odlew z mostkiem

166

Z ARC, już nie mogę rzucić CGColorRefsię id. Dowiedziałem się, że muszę wykonać obsadę z mostkiem. Według clang Docs :

Bridged obsada jest oddanych C-styl opatrzone jednym z trzech słów kluczowych:

(__bridge T) oprzutuje operand na typ docelowy T. Jeśli T jest typem wskaźnika obiektu, który można przechowywać, to opmusi mieć typ wskaźnika, którego nie można przechowywać. Jeśli Tjest nieprzechowywalnym typem wskaźnika, to op musi mieć możliwy do utrzymania typ wskaźnika obiektu. W przeciwnym razie odlew jest źle uformowany. Nie ma przeniesienia własności, a ARC nie wprowadza żadnych operacji zachowania.

(__bridge_retained T) oprzutuje operand, który musi mieć typ wskaźnika obiektu, który można zachować, na typ docelowy, który musi być typem wskaźnika, którego nie można zachować. ARC zachowuje wartość, z zastrzeżeniem zwykłych optymalizacji wartości lokalnych, a odbiorca jest odpowiedzialny za zbilansowanie tego +1.

(__bridge_transfer T) oprzutuje operand, który musi mieć nieprzechowywalny typ wskaźnika, na typ docelowy, który musi być zachowanym typem wskaźnika obiektu. ARC zwolni wartość na końcu otaczającego pełnego wyrażenia, z zastrzeżeniem zwykłych optymalizacji wartości lokalnych.

Rzuty te są wymagane do przenoszenia obiektów do i poza kontrolę ARC; zobacz uzasadnienie w sekcji dotyczącej konwersji zachowywalnych wskaźników obiektów.

Używanie odlewu __bridge_retainedlub __bridge_transferwyłącznie do przekonania ARC do emitowania odpowiednio niezrównoważonego zatrzymania lub uwolnienia jest kiepską formą.

W jakich sytuacjach użyłbym każdego z nich?

Na przykład CAGradientLayerma colorswłaściwość, która akceptuje tablicę CGColorRefs. Domyślam się, że powinienem __brigetutaj użyć , ale dokładnie, dlaczego powinienem (lub nie powinienem), nie jest jasne.

Bez Morrowless
źródło
17
Czy oglądałeś już sesję 323 WWDC 2011? To wyjaśnia ARC znacznie lepiej niż ja mogłem tutaj. Obejmuje wszystkie szczegóły od początku do końca. To obowiązkowa sesja dla każdego programisty Mac / iOS.
brązowy
To też może pomóc: stackoverflow.com/questions/14352494/…
Ewan Mellor
Link do sesji WWDC, znalezienie go nie było trywialne: developer.apple.com/videos/play/wwdc2011/323 - Odpowiedni fragment jest o 23:15
Daniel

Odpowiedzi:

215

Zgadzam się, że opis jest mylący. Ponieważ właśnie je zrozumiałem, spróbuję podsumować:

  • (__bridge_transfer <NSType>) oplub alternatywnie CFBridgingRelease(op)jest używany do zużywania liczby zatrzymań a CFTypeRefpodczas przesyłania jej do ARC. Może to być również reprezentowane przezid someObj = (__bridge <NSType>) op; CFRelease(op);

  • (__bridge_retained <CFType>) oplub alternatywnie CFBridgingRetain(op)jest używany do przekazania NSObjectlądu CF, dając mu +1 do zatrzymania. Powinieneś postępować z CFTypeRefutworzonym w ten sposób wynikiem tak samo, jak z wynikiem CFStringCreateCopy(). Może to być również reprezentowane przezCFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;

  • __bridgepo prostu rzuca między krainą wskaźnika i ziemią obiektu-C. Jeśli nie masz ochoty korzystać z powyższych konwersji, użyj tej.

Może to jest pomocne. Ja osobiście wolę CFBridging…makra bardziej niż zwykłe rzuty.

małpa
źródło
Czy liczba obiektów zachowanych zwiększa się o 1 łuk, gdy używasz __bridge_transfer? W przeciwnym razie mogłoby się wydawać, że w momencie wywołania CFRelease () obiekt znika i nic nie wskazuje. Podobnie, gdy używasz __bridge_retain, czy ARC zmniejsza liczbę zatrzymań operacji o 1? W przeciwnym razie wydaje się, że obiekt nigdy nie zostałby prawidłowo zwolniony.
Tony
2
Będąc w krainie ARC, nie myślisz już o zachowaniu liczników, tylko o mocnych i słabych odniesieniach.
małpia
4
Tak, jeśli jesteś tylko w łuku silny / słaby, wystarczyłoby, jednak kiedy przenosisz obiekty między środowiskami łukowymi i nie-łukowymi, nadal musisz pomyśleć o implikacjach liczby zatrzymań pod maską
Tony
3
Nie całkiem. Musisz pomyśleć tylko o wejściu i wyjściu z ziemi ARC. Przypomina to chwytanie autoreleasingu. (co ciekawe: ARC naprawia powszechny wzorzec, taki jak wyciąganie obiektu ze słownika, a następnie usuwanie go przed użyciem itp.)
monkeydom Kwietnia
3
użycie narzędzia Analyzer (shift + command + B) może pomóc w rozwiązaniu tego rodzaju wątpliwości, ponieważ powie w języku naturalnym, czy bieżący kod przecieka pamięć. Jeśli tak, prawdopodobnie używasz odlewu podtrzymującego, podczas gdy powinieneś używać odlewu nie zatrzymującego. jeśli Analizator nie ostrzega Cię o niczym w tych liniach kodu, prawdopodobnie dobrze sobie radzisz z obecnym kodem
Fabio Napodano.
55

Znalazłem inne wyjaśnienie w dokumentacji iOS, które moim zdaniem jest łatwiejsze do zrozumienia:

  • __bridge przenosi wskaźnik między Objective-C i Core Foundation bez przenoszenia prawa własności.

  • __bridge_retained (CFBridgingRetain)rzuca wskaźnik Objective-C na wskaźnik Core Foundation, a także przenosi własność na Ciebie.

    Jesteś odpowiedzialny za wywołanie CFRelease lub powiązanej funkcji w celu zrzeczenia się własności obiektu.

  • __bridge_transfer (CFBridgingRelease)Przenosi non-Objective-C wskaźnik do Objective-C , a także przenosi prawo własności do ARC.

    ARC odpowiada za zrzeczenie się własności obiektu.

Źródło: bezpłatne typy mostowe

gregschlom
źródło
33

W ramach kontynuacji, w tym konkretnym przypadku, jeśli korzystasz z systemu iOS, Apple zaleca użycie UIColor i jego -CGColormetody w celu zwrócenia CGColorRef do NSArray colors. W Transitioning to ARC Release Notes , w sekcji „The Compiler Handles CF Objects Returned From Cocoa Methods”, wskazano, że użycie metody, takiej jak -CGColorzwracająca obiekt Core Foundation, będzie automatycznie obsługiwane przez kompilator.

Dlatego sugerują użycie kodu podobnego do następującego:

CAGradientLayer *gradientLayer = (CAGradientLayer *)[self layer];
gradientLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor],
                                                 (id)[[UIColor lightGrayColor] CGColor], nil];

Zauważ, że w tej chwili w przykładowym kodzie Apple brakuje rzutowania (id), które mam powyżej, co jest nadal konieczne, aby uniknąć błędu kompilatora.

Brad Larson
źródło
Jeśli wolisz, zazwyczaj możesz po prostu rzucić pierwszy z obiektów na (id) zamiast wszystkich.
Philippe Sabourin
1
To pytanie dotyczy przesyłania za pomocą ARC, gdzie wklejony kod jest niezgodny z prawem.
Joey Hagedorn
11
@JoeyHagedorn - Być może przegapiłeś moje odniesienie do dokumentacji ARC w pierwszym zdaniu mojej odpowiedzi, ale nie tylko jest to ważne w ARC, jest to zalecane podejście do dostarczania referencji CGColorRef do NSArrays z tych metod konwertera UIColor. Ja i wielu innych używam dokładnie tego kodu w aplikacjach obsługujących ARC. Natychmiastowe rzutowanie na (id) z metody, która zwraca obiekt Core Foundation automatycznie łączy ten obiekt z ARC.
Brad Larson