NSString zu CFStringRef und CFStringRef zu NSString in ARC?

87

Ich versuche zu verstehen, wie man NSStringvon einem CFStringRefin ARC einen bekommt ? Das Gleiche gilt für die entgegengesetzte Richtung, CFStringRefum NSStringin ARC?

Was ist der richtige Weg, um dies zu tun, ohne Speicherlecks zu verursachen?

zumzum
quelle
4
CFStringRef foo (__bridge CFStringRef)theNSString;undNSString *bar = (__bridge NSString *)theCFString;
Können Sie im Detail erklären, was wirklich passiert, wenn diese beiden Optionen verwendet werden?
Zumzum
Nicht ganz. Ich benutze ARC nicht, also weiß ich nur, dass Sie dies tun müssen, aber nicht das Warum.
1
@GabrielePetronella ARC sollte das Codieren vereinfachen, den Code kürzer und lesbarer machen und die Möglichkeit menschlicher Fehler verringern. So, nun statt mit der Referenzzähler kümmern durch retaining und releaseObjekte -ing, müssen wir jetzt „schön“ Abgüsse wie verwenden __bridge_transfer, __unsafe_unretainedund __autoreleasing. Niemand hat keine Zeit dafür. (Und im Ernst, es ist schwieriger zu lesen. Meiner Meinung nach hat es die Speicherverwaltung überhaupt nicht erleichtert.)
1
@ H2CO3 danke für die Antwort. Ich bin nicht einverstanden, besonders mit dem letzten Satz, aber ich respektiere Ihren Standpunkt :)
Gabriele Petronella

Antworten:

175

Typischerweise

NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;

und

CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;

Wenn Sie wissen möchten, warum das __bridgeSchlüsselwort vorhanden ist, lesen Sie die Apple-Dokumentation . Dort finden Sie:

__bridge überträgt einen Zeiger zwischen Objective-C und Core Foundation ohne Eigentumsübertragung.

__bridge_retainedoder CFBridgingRetainwirft einen Objective-C-Zeiger auf einen Core Foundation-Zeiger und überträgt Ihnen auch das Eigentum. Sie sind dafür verantwortlich, CFRelease oder eine verwandte Funktion aufzurufen, um das Eigentum an dem Objekt aufzugeben.

__bridge_transferoder CFBridgingReleaseverschiebt einen Nicht-Objective-C-Zeiger auf Objective-C und überträgt auch das Eigentum an ARC. ARC ist dafür verantwortlich, das Eigentum an dem Objekt aufzugeben.

Dies bedeutet, dass Sie in den oben genannten Fällen das Objekt umwandeln, ohne den Eigentümer zu ändern. Dies bedeutet, dass Sie in keinem Fall für den Speicher der Zeichenfolgen verantwortlich sind.

Es kann auch vorkommen, dass Sie das Eigentum aus irgendeinem Grund übertragen möchten.

Betrachten Sie zum Beispiel das folgende Snippet

- (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 einem solchen Fall möchten Sie möglicherweise eine speichern, CFReleaseindem Sie das Eigentum beim Casting übertragen.

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

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

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

Das Eigentum an strwurde übertragen, daher wird ARC jetzt den Speicher für Sie freigeben.

Auf der anderen Art und Weise um Sie werfen können , NSString *um ein CFStringmit einem __bridge_retainedgegossenen, so dass Sie das Objekt besitzen werden , und Sie werden ausdrücklich darauf haben zu lösen , indem Sie CFRelease.


Zum Abschluss können Sie haben

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
quelle
Vielen Dank, das ist nicht wirklich intuitiv, aber dank dir, Lektion gelernt
Sulfkain
@: kleine Frage. Also, wenn wir ARC verwenden. wann NSString->CFStringsollten wir verwenden __bridge. aber wann CFString->NSStringsollten wir verwenden __bride_transfer. ? Und jede Nebenwirkung, wenn wir verwenden, CFReleasewenn wir nicht auch brauchen. danke :)
hqt
@hqt, wenn Sie den "einfachen" Weg wollen, ja, was Sie sagen, ist richtig. Außerdem sollte ein Extra CFReleaseIhr Programm vernünftigerweise zum Absturz bringen, da Sie am Ende eine nicht übereinstimmende Aufbewahrungs- / Freigabeoperation haben und schließlich einen NULLZeiger freigeben .
Gabriele Petronella