web-dev-qa-db-ja.com

ARCとCFRelease?

少し混乱しています。私が読んだすべての場所で、ARCを使用する場合でも、意味のあるコア基盤オブジェクトをリリースする必要があることを示唆しています。ARCはそれらを管理しません。ただし、CFReleaseを使用したCFメソッド/オブジェクトを使用するメソッドがありますが、それが原因でアプリがクラッシュしました。 CFReleasesのコメントを外すと問題は解決しますが、メモリリークが発生したと思いますか?

誰かがリリースする必要があるものとリリースしないもの、またはこのコードで間違っている他の何かを説明できますか?

+ (NSString *) fileExtensionForMimeType:(NSString *)type
{
    CFStringRef mimeType = (__bridge CFStringRef)type;
    CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
    CFStringRef extension = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);

    NSString *ext = (__bridge NSString *)extension;

    // CFRelease(mimeType);
    // CFRelease(uti);
    // CFRelease(extension);

    return ext;
}

コメントアウトされた3つのCFRelease呼び出しは、前述のように問題を修正しますが、それが間違っていることはわかっています。私は何をすべきですか?

33
PaReeOhNos

mimeTypeを所有していないため、リリースできません。 __bridgeキャストで所有権を譲渡しませんでした。

utiを作成したので、リリースする必要があります。

extensionも作成したのでリリースする必要がありますが、extで問題が発生する可能性があります。代わりに、所有権をextに譲渡してください。

私は次のことを提案します:

+ (NSString *) fileExtensionForMimeType:(NSString *)type {
    CFStringRef mimeType = (__bridge CFStringRef)type;
    CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
    CFStringRef extension = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);

    NSString *ext = (__bridge_transfer NSString *)extension;

    // CFRelease(mimeType); // not owned
    if (uti) CFRelease(uti);
    // CFRelease(extension); // ownership was transferred

    return ext;
}
37
rmaddy

チェックアウト WWDC 2012-Modern Objective-C これはCoreFoundationオブジェクトとARCの新しいガイドラインの概要を示しています。そのビデオの37時35分頃です。つまり、名前にCopyまたはCreateが含まれるCoreFoundation関数は、所有権をアプリに譲渡したオブジェクトを作成し、アプリはそれを解放する責任があります。

とにかく、名前にCopyまたはCreateが含まれるCoreFoundationメソッドを介して所有権が譲渡された場合は、完了したらCFReleaseを使用して手動で解放できます。 、または、より簡単に、所有権をARCに譲渡して、それを処理させることができます。歴史的に、所有権をARCに譲渡するために、__bridge_transferを使用していましたが、現在はCFBridgingReleaseを推奨しています(後者は前者の単なるマクロですが)。そして、明らかに、名前にCopyまたはCreateが含まれる関数以外のメカニズムを介して取得した、Core Foundationオブジェクトがある場合は、CFReleaseも使用しないでください。また、所有権をARCに譲渡することもありません。

実例として、このメソッドはあなたが望むことを達成します:

+ (NSString *) fileExtensionForMimeType:(NSString *)type {

    NSString *uti = CFBridgingRelease(UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType,
                                                                            (__bridge CFStringRef)type,
                                                                            NULL));

    return CFBridgingRelease(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)uti,
                                                             kUTTagClassFilenameExtension));
}
15
Rob

一般的に言って、最初のCFRelease(mimeType)行にコメントを付け、次の2行(CFRelease(uti)とCFRelease(extension))のコメントを外す必要があると思います。 NSStringを入力するためにフリーダイヤルブリッジをキャストすると、ARCがリリースを処理します。ただし、utiと拡張子はCFStringとして作成/コピーされます。 ARCはそれらの処理方法を認識しないため(ARCはNSObjectのコンパイラ機能であることを思い出してください)、CFリリースする必要があります。

0
onevcat