NSString to CFStringRef i CFStringRef to NSString w ARC?

87

Próbuję zrozumieć prawidłowy sposób uzyskiwania odpowiedzi NSStringz CFStringRefARC? To samo dotyczy jazdy w przeciwnym kierunku, CFStringRefdo NSStringARC?

Jaki jest właściwy sposób, aby to zrobić bez tworzenia wycieków pamięci?

zumzum
źródło
4
CFStringRef foo (__bridge CFStringRef)theNSString;iNSString *bar = (__bridge NSString *)theCFString;
Czy mógłbyś szczegółowo wyjaśnić, co naprawdę się dzieje, gdy używane są te dwie opcje?
zumzum
Nie do końca. Nie używam ARC, więc wiem tylko, że musisz to zrobić, ale nie wiem dlaczego.
1
@GabrielePetronella ARC miał na celu ułatwienie kodowania, skrócenie i czytelność kodu oraz zmniejszenie możliwości błędów ludzkich. Więc teraz, zamiast zająć się liczy odniesienia przez retainnia i release-ing obiektów, musimy teraz używać „piękne” jak odlewy __bridge_transfer, __unsafe_unretainedi __autoreleasing. Nikt nie ma na to czasu. (A poważnie, trudniej go czytać. Moim zdaniem w ogóle nie ułatwiło to zarządzania pamięcią.)
1
@ H2CO3 dziękuję za odpowiedź. Zdecydowanie się nie zgadzam, szczególnie z ostatnim zdaniem, ale szanuję Twój punkt widzenia :)
Gabriele Petronella

Odpowiedzi:

177

Zwykle

NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;

i

CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;

Teraz, jeśli chcesz wiedzieć, dlaczego __bridgejest tam słowo kluczowe, możesz zapoznać się z dokumentacją Apple . Znajdziesz tam:

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

__bridge_retainedlub CFBridgingRetainrzuca 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_transferlub CFBridgingReleaseprzenosi wskaźnik nie będący celem C do celu C, a także przenosi własność do ARC. ARC odpowiada za zrzeczenie się własności obiektu.

Co oznacza, że ​​w powyższych przypadkach rzucasz obiekt bez zmiany właściciela. Oznacza to, że w żadnym przypadku nie będziesz odpowiedzialny za obsługę pamięci ciągów.

Może się również zdarzyć, że z jakiegoś powodu zechcesz przenieść własność.

Weźmy na przykład następujący fragment

- (void)sayHi {
    CFStringRef str = CFStringCreateWithCString(NULL, "Hello World!", kCFStringEncodingMacRoman);

    NSString * aNSString = (__bridge NSString *)str;

    NSLog(@"%@", aNSString);

    CFRelease(str); //you have to release the string because you created it with a 'Create' CF function
}

w takim przypadku możesz zechcieć zapisać CFRelease, przenosząc własność podczas przesyłania.

- (void)sayHi {
    CFStringRef str = CFStringCreateWithCString(NULL, "Hello World!", kCFStringEncodingMacRoman);

    NSString * aNSString = (__bridge_transfer NSString *)str;
// or alternatively
    NSString * aNSString = (NSString *)CFBridgingRelease(str);

    NSLog(@"%@", aNSString);
}

Własność strzostała przeniesiona, więc teraz ARC włączy się i zwolni pamięć.

Z drugiej strony możesz rzutować a NSString *na za CFStringpomocą __bridge_retainedrzutowania, dzięki czemu będziesz właścicielem obiektu i będziesz musiał jawnie zwolnić go za pomocą CFRelease.


Aby to zakończyć, możesz mieć

NSString → CFString

// Don't transfer ownership. You won't have to call `CFRelease`
CFStringRef str = (__bridge CFStringRef)string;

// Transfer ownership (i.e. get ARC out of the way). The object is now yours and you must call `CFRelease` when you're done with it
CFStringRef str = (__bridge_retained CFStringRef)string // you will have to call `CFRelease`

CFString → NSString

// Don't transfer ownership. ARC stays out of the way, and you must call `CFRelease` on `str` if appropriate (depending on how the `CFString` was created)
NSString *string = (__bridge NSString *)str;

// Transfer ownership to ARC. ARC kicks in and it's now in charge of releasing the string object. You won't have to explicitly call `CFRelease` on `str`
NSString *string = (__bridge_transfer NSString *)str;
Gabriele Petronella
źródło
Bardzo dziękuję, to nie jest tak naprawdę intuicyjne, ale dzięki tobie lekcja wyciągnięta
Sulfkain
@: małe pytanie. więc jeśli używamy ARC. kiedy NSString->CFStringpowinniśmy użyć __bridge. ale kiedy CFString->NSStringpowinniśmy użyć __bride_transfer. ? I każdy efekt uboczny, jeśli używamy, CFReleasegdy nie potrzebujemy. dzięki :)
hqt
@hqt, jeśli chcesz „łatwego” sposobu, tak, to, co mówisz, jest poprawne. Ponadto, dodatkowy CFReleasepowinien rozsądnie zawiesić twój program, ponieważ skończysz z niedopasowaną operacją zatrzymania / zwolnienia, ostatecznie zwalniając NULLwskaźnik.
Gabriele Petronella