Da NSString a CFStringRef e da CFStringRef a NSString in ARC?


87

Sto cercando di capire il modo corretto di ottenere un NSStringda un CFStringRefin ARC? Lo stesso per andare nella direzione opposta, CFStringRefa NSStringin ARC?

Qual è il modo corretto per farlo senza creare perdite di memoria?


4
CFStringRef foo (__bridge CFStringRef)theNSString;eNSString *bar = (__bridge NSString *)theCFString;

Potresti spiegare nei dettagli cosa sta realmente accadendo quando vengono utilizzate queste due opzioni?
zumzum

Non proprio. Non uso ARC, quindi tutto quello che so è che devi farlo, ma non il perché.

1
@GabrielePetronella ARC avrebbe dovuto rendere la codifica facile, il codice più breve e più leggibile e ridurre la possibilità di errori umani. Quindi, ora invece di dover occuparci dei conteggi di riferimento inserendo retaine releaserimuovendo oggetti, dobbiamo ora usare cast "belli" come __bridge_transfer, __unsafe_unretainede __autoreleasing. Nessuno non ha tempo per questo. (E seriamente, è più difficile da leggere. Secondo me, non ha facilitato affatto la gestione della memoria.)

1
@ H2CO3 grazie per la risposta. Non sono assolutamente d'accordo, soprattutto con l'ultima frase, ma rispetto il tuo punto di vista :)
Gabriele Petronella

Risposte:


177

Tipicamente

NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;

e

CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;

Ora, se vuoi sapere perché c'è la __bridgeparola chiave, puoi fare riferimento alla documentazione di Apple . Lì troverai:

__bridge trasferisce un puntatore tra Objective-C e Core Foundation senza trasferimento di proprietà.

__bridge_retainedoppure CFBridgingRetainlancia un puntatore Objective-C a un puntatore Core Foundation e trasferisce anche la proprietà a te. Sei responsabile di chiamare CFRelease o una funzione correlata per rinunciare alla proprietà dell'oggetto.

__bridge_transfero CFBridgingReleasesposta un puntatore non-Objective-C su Objective-C e trasferisce anche la proprietà ad ARC. ARC è responsabile della rinuncia alla proprietà dell'oggetto.

Ciò significa che nei casi sopra si esegue il casting dell'oggetto senza modificare la proprietà. Ciò implica che in nessuno dei due casi sarai responsabile della gestione della memoria delle stringhe.

Potrebbe anche esserci il caso in cui desideri trasferire la proprietà per qualche motivo.

Ad esempio, considera il seguente frammento

- (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
}

in tal caso potresti voler salvare un CFReleasetrasferendo la proprietà durante la trasmissione.

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

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

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

La proprietà di strè stata trasferita, quindi ora ARC entrerà in azione e rilascerà la memoria per te.

Al contrario, puoi lanciare un NSString *a CFStringusando un __bridge_retainedcast, in modo da essere proprietario dell'oggetto e dovrai rilasciarlo esplicitamente usando CFRelease.


Per concludere puoi avere

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;

Grazie mille, questo non è molto intuitivo, ma grazie a te, lezione imparata
Sulfkain

@: piccola domanda. quindi se usiamo ARC. quando NSString->CFString, dovremmo usare __bridge. ma quando CFString->NSString, dovremmo usare __bride_transfer. ? E qualsiasi effetto collaterale, se lo usiamo CFReleasequando non ne abbiamo bisogno. grazie :)
hqt

@hqt, se vuoi il modo "facile", sì, quello che dici è corretto. Inoltre, un extra CFReleasedovrebbe ragionevolmente mandare in crash il tuo programma, dal momento che finirai con un'operazione di conservazione / rilascio non corrispondente, rilasciando eventualmente un NULLpuntatore.
Gabriele Petronella
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.