ARCのNSStringからCFStringRefおよびCFStringRefからNSString?


87

ARCでNSStringからを取得する正しい方法を理解しようとしていますCFStringRefか?、反対の方向に行くために同じCFStringRefNSStringARCに?

メモリリークを発生させずにこれを行う正しい方法は何ですか?


4
CFStringRef foo (__bridge CFStringRef)theNSString;およびNSString *bar = (__bridge NSString *)theCFString;

これらの2つのオプションを使用した場合、実際に何が起こっているのかを詳しく説明していただけますか?
zumzum 2013年

完全ではありません。私はARCを使用していないので、私が知っているのは、これを実行する必要があるということだけですが、その理由

1
@GabrielePetronella ARCは、コーディングを簡単にし、コードを短くして読みやすくし、人的エラーの可能性を減らすことになっています。だから、今の代わりにして参照カウントの世話をするのでretainINGのとreleaseオブジェクトを-ing、我々は今のような「美しい」キャストを使用しなければならない__bridge_transfer__unsafe_unretained__autoreleasing。誰もそのための時間がありません。(そして真剣に、それは読みにくいです。私の意見では、それはメモリ管理をまったく促進しませんでした。)

1
@ H2CO3回答ありがとうございます。私は特に最後の文に強く反対しますが、あなたの見解を尊重します:)
Gabriele Petronella 2013年

回答:


177

通常、

NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;

そして

CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;

ここで、__bridgeキーワードが存在する理由を知りたい場合は、Appleのドキュメントを参照してください。そこにあなたが見つけるでしょう:

__bridge 所有権を譲渡せずに、Objective-CとCoreFoundationの間でポインターを譲渡します。

__bridge_retainedまたはCFBridgingRetain、Objective-CポインターをCore Foundationポインターにキャストし、所有権をユーザーに譲渡します。CFReleaseまたは関連する関数を呼び出して、オブジェクトの所有権を放棄する必要があります。

__bridge_transferまたはCFBridgingRelease、Objective-C以外のポインタをObjective-Cに移動し、所有権をARCに譲渡します。ARCは、オブジェクトの所有権を放棄する責任があります。

つまり、上記の場合、所有権を変更せずにオブジェクトをキャストしているということです。これは、どちらの場合も、文字列のメモリの処理を担当することを意味します。

また、何らかの理由で所有権を譲渡したい場合もあります。

たとえば、次のスニペットについて考えてみます。

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

このような場合CFRelease、キャスト時に所有権を譲渡して保存することをお勧めします。

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

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

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

の所有権strが譲渡されたため、ARCが起動してメモリを解放します。

逆に、キャストを使用NSString *してCFStringをに__bridge_retainedキャストすることもできます。そのため、オブジェクトを所有し、を使用してオブジェクトを明示的に解放する必要がありますCFRelease


それをまとめるためにあなたは持つことができます

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;

どうもありがとうございました、これは本当に直感的ではありませんが、あなたのおかげで、学んだ教訓
Sulfkain 2014年

@:ちょっとした質問。したがって、ARCを使用する場合。の場合NSString->CFString、を使用する必要があります__bridge。ただし、の場合はCFString->NSString、を使用する必要があります__bride_transfer。?そして、CFRelease必要のないときに使用すれば、副作用もあります。ありがとう:)
hqt 2014

@hqt、「簡単な」方法が必要な場合は、そうです、あなたの言うことは正しいです。また、CFRelease保持/解放操作の不一致が発生し、最終的にNULLポインタが解放されるため、エクストラはプログラムを合理的にクラッシュさせるはずです。
Gabriele Petronella 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.