NSString ke CFStringRef dan CFStringRef ke NSString di ARC?

89

Saya mencoba memahami cara yang benar untuk mendapatkan NSStringdari a CFStringRefdi ARC? Sama untuk pergi ke arah sebaliknya, CFStringRefke NSStringdalam ARC?

Apa cara yang benar untuk melakukan ini tanpa menyebabkan kebocoran memori?

zumzum
sumber
4
CFStringRef foo (__bridge CFStringRef)theNSString;danNSString *bar = (__bridge NSString *)theCFString;
Bisakah Anda menjelaskan apa yang sebenarnya terjadi secara detail ketika kedua opsi itu digunakan?
zumzum
Tidak terlalu. Saya tidak menggunakan ARC, jadi yang saya tahu adalah Anda harus melakukan ini, tetapi bukan alasannya.
1
@GabrielePetronella ARC seharusnya membuat pengkodean menjadi mudah, kode lebih pendek dan lebih mudah dibaca dan mengurangi kemungkinan kesalahan manusia. Jadi, sekarang alih-alih harus mengurus jumlah referensi dengan objek retaining dan release, sekarang kita harus menggunakan pemain "cantik" seperti __bridge_transfer, __unsafe_unretaineddan __autoreleasing. Tidak ada yang tidak punya waktu untuk itu. (Dan sungguh, ini lebih sulit untuk dibaca. Menurut saya, itu tidak memfasilitasi manajemen memori sama sekali.)
1
@ H2CO3 terima kasih atas jawabannya. Saya sangat tidak setuju, terutama dengan kalimat terakhir, tapi saya menghormati sudut pandang Anda :)
Gabriele Petronella

Jawaban:

180

Khas

NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;

dan

CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;

Sekarang, jika Anda ingin tahu mengapa __bridgekata kunci itu ada, Anda bisa merujuk ke dokumentasi Apple . Di sana Anda akan menemukan:

__bridge mentransfer penunjuk antara Objective-C dan Core Foundation tanpa pengalihan kepemilikan.

__bridge_retainedatau CFBridgingRetainmelemparkan pointer Objective-C ke pointer Core Foundation dan juga mentransfer kepemilikan kepada Anda. Anda bertanggung jawab untuk memanggil CFRelease atau fungsi terkait untuk melepaskan kepemilikan objek.

__bridge_transferatau CFBridgingReleasememindahkan penunjuk non-Objective-C ke Objective-C dan juga mentransfer kepemilikan ke ARC. ARC bertanggung jawab untuk melepaskan kepemilikan objek.

Artinya, dalam kasus di atas Anda mentransmisikan objek tanpa mengubah kepemilikan. Ini menyiratkan bahwa dalam kedua kasus Anda tidak akan bertanggung jawab untuk menangani memori string.

Mungkin juga ada kasus di mana Anda ingin mentransfer kepemilikan karena alasan tertentu.

Misalnya perhatikan cuplikan berikut

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

dalam kasus seperti itu, Anda mungkin ingin menyimpan CFReleasedengan mentransfer kepemilikan saat mentransmisi.

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

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

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

Kepemilikan strtelah ditransfer, jadi sekarang ARC akan masuk dan melepaskan memori untuk Anda.

Sebaliknya, Anda dapat mentransmisikan a NSString *ke CFStringmenggunakan __bridge_retainedcast, sehingga Anda akan memiliki objek tersebut dan harus melepaskannya secara eksplisit dengan menggunakan CFRelease.


Untuk menyelesaikannya, Anda dapat memiliki

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
sumber
Terima kasih banyak, ini tidak terlalu intuitif, tapi terima kasih, pelajaran yang didapat
Sulfkain
@: pertanyaan kecil. jadi jika kita menggunakan ARC. kapan NSString->CFString, kita harus menggunakan __bridge. tapi kapan CFString->NSString, kita harus menggunakan __bride_transfer. ? Dan efek sampingnya, jika kita gunakan CFReleasesaat kita tidak membutuhkannya juga. terima kasih :)
hqt
@hqt, kalau mau cara yang 'gampang' ya apa yang kamu katakan itu benar. Juga, tambahan CFReleaseseharusnya membuat program Anda mogok, karena Anda akan berakhir dengan operasi pertahankan / rilis yang tidak sesuai, yang akhirnya melepaskan NULLpenunjuk.
Gabriele Petronella