28 votes

ARC et CFRelease?

Je suis un peu confus. Partout où je l'ai lu, suggèrent que lors de l'utilisation de l'ARC, vous avez encore besoin de libérer de base objets de la fondation qui fait sens, l'ARC n'a pas les gérer. Cependant, j'ai une méthode qui utilise des FC, les méthodes des objets que j'ai utilisé CFRelease , mais qui ensuite entraîné l'application crash. Décommentant la ma CFReleases résout le problème, mais alors je suis en supposant que j'ai une fuite de mémoire?

Quelqu'un pourrait-il expliquer de quelles choses doivent libérer et qui ne le sont pas, ou tout autre chose qui ne va pas dans ce code?

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

Les trois commenté CFRelease des appels résoudre le problème comme mentionné, mais je sais que c'est faux. Que dois-je faire?

30voto

rmaddy Points 79279

Vous ne pouvez pas libérer mimeType parce que vous ne le possédez pas. Vous n'avez pas transféré la propriété avec le cast __bridge .

Vous devriez libérer uti depuis que vous l'avez créé.

Vous devez également libérer extension puisque vous l'avez également créé, mais cela causera probablement des problèmes avec ext . Transférez plutôt la propriété à ext .

Je suggère ce qui suit:

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

12voto

Rob Points 70987

Découvrez la WWDC 2012 - Moderne Objective-C qui décrit les nouvelles lignes directrices pour les principaux objets de la Fondation et de l'ARC. C'est environ 37:35 dans cette vidéo. En bref, Fondement de Base avec des fonctions d' Copy ou Create dans le nom de créer un objet qui a transféré la propriété à votre application, et votre application est responsable de la relâcher.

De toute façon, si la propriété a été transférée par l'intermédiaire d'un Fondement de Base de la méthode avec Copy ou Create dans le nom, vous pouvez libérer manuellement, il avec CFRelease quand vous avez fini avec elle, ou, plus facile, vous pouvez transférer la propriété à l'ARC et qu'elle prenne soin d'elle. Historiquement, le transfert de propriété à l'ARC, nous avons utilisé __bridge_transfer, mais ils recommandent maintenant CFBridgingRelease (même si ce dernier est juste une macro pour l'ancien). Et, évidemment, si vous avez quelques Fondement de Base de l'objet que vous avez récupéré via un autre mécanisme autre que d'une fonction avec des Copy ou Create dans le nom, vous ne devez ni CFRelease , ni en transférer la propriété à l'ARC.

À titre d'illustration, cette méthode accomplit ce que vous voulez:

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

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

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

0voto

onevcat Points 2390

De manière générale, je pense que vous devriez essayer de commenter la première ligne CFRelease (mimeType) et décommenter les deux lignes suivantes: CFRelease (uti) et CFRelease (extension). Vous lancez un pont sans frais pour entrer NSString et ARC gérera la version. Mais l'uti et l'extension sont créés / copiés en tant que CFString. ARC ne saura pas comment les gérer (rappelez-vous que ARC est une fonction de compilation pour NSObject), vous devez donc les libérer de CF.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X