Подтвердить что ты не робот

ARC и CFRelease?

Я немного смущен. Везде, где я читал, предположим, что при использовании ARC вам все равно нужно освободить основные объекты фундамента, что имеет смысл, ARC не справляется с ними. Тем не менее, у меня есть метод, который использует некоторые методы/объекты CF, которые я использовал CFRelease, но это привело к сбою приложения. Раскомментирование моего CFRelease устраняет проблему, но затем я предполагаю, что у меня есть утечка памяти?

Может кто-нибудь объяснить, какие вещи нужно выпускать, а какие нет или что-то еще не так с этим кодом?

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

Три закомментированных вызова CFRelease исправляют проблему, как упоминалось, но я знаю, что это неправильно. Что я должен делать?

4b9b3361

Ответ 1

Вы не можете освободить 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;
}

Ответ 2

Отъезд WWDC 2012 - Современный Objective-C, в котором описываются новые рекомендации для объектов Core Foundation и ARC. Это примерно 37:35 в этом видео. Короче говоря, функции Core Foundation с Copy или Create в имени создают объект, который передал право собственности на ваше приложение, и ваше приложение несет ответственность за его освобождение.

В любом случае, если право собственности передано с помощью метода Core Foundation с Copy или Create в имени, вы можете либо вручную отпустить его с помощью CFRelease, когда вы закончите с ним, либо, что проще, вы может передать право собственности в ARC и позволить ему позаботиться об этом. Исторически для передачи права собственности на ARC мы использовали __bridge_transfer, но теперь они рекомендуют CFBridgingRelease (хотя последний является всего лишь макросом для первого). И, очевидно, если у вас есть объект Core Foundation, который вы извлекли с помощью другого механизма, отличного от функции с Copy или Create в имени, вы не должны ни CFRelease, ни передать право собственности в ARC.

В качестве иллюстрации этот метод выполняет то, что вы хотите:

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

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

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

Ответ 3

В общем, я думаю, вы должны попытаться прокомментировать первую строку CFRelease (mimeType) и раскомментировать следующие две строки: CFRelease (uti) и CFRelease (расширение). Вы передаете бесплатный мост для ввода NSString, и ARC будет обрабатывать выпуск. Но uti и расширение создаются/копируются как CFString. ARC не будет знать, как с ними справиться (помните, что ARC - это функция компилятора для NSObject), поэтому вам нужно их освободить.