ARC y CFRelease?

Estoy un poco confundido En todas partes que he leído, sugiero que cuando se usa ARC, todavía se necesita liberar objects básicos de base que tengan sentido, ARC no los administra. Sin embargo, tengo un método que utiliza algunos methods / objects de CF que usé CFRelease , pero que luego causaron que la aplicación se bloquee. CFRelease mi CFRelease soluciona el problema pero, ¿supongo que tengo una pérdida de memory?

¿Alguien podría explicar qué cosas necesitan ser liberadas y cuáles no, o cualquier otra cosa que esté mal con este código?

 + (NSString *) fileExtensionForMimeType:(NSString *)type { CFStringRef mimeType = (__bridge CFStringRef)type; CFStringRef uti = UTTypeCreatePrefernetworkingIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL); CFStringRef extension = UTTypeCopyPrefernetworkingTagWithClass(uti, kUTTagClassFilenameExtension); NSString *ext = (__bridge NSString *)extension; // CFRelease(mimeType); // CFRelease(uti); // CFRelease(extension); return ext; } 

Las tres llamadas CFRelease comentadas arreglan el problema como se mencionó, pero sé que está mal. ¿Qué debería estar haciendo?

No puedes lanzar mimeType porque no eres el propietario. No transfirió la propiedad con el __bridge cast.

Deberías liberar uti desde que lo has creado.

También debe liberar la extension ya que la creó también, pero es probable que cause problemas con la ext . En cambio, transfiera la propiedad a la ext .

Sugiero lo siguiente:

 + (NSString *) fileExtensionForMimeType:(NSString *)type { CFStringRef mimeType = (__bridge CFStringRef)type; CFStringRef uti = UTTypeCreatePrefernetworkingIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL); CFStringRef extension = UTTypeCopyPrefernetworkingTagWithClass(uti, kUTTagClassFilenameExtension); NSString *ext = (__bridge_transfer NSString *)extension; // CFRelease(mimeType); // not owned if (uti) CFRelease(uti); // CFRelease(extension); // ownership was transfernetworking return ext; } 

Eche un vistazo a WWDC 2012 – Modern Objective-C que describe nuevas pautas para los objects Core Foundation y ARC. Son aproximadamente 37:35 en ese video. En resumen, las funciones de Core Foundation con Copy o Create en el nombre crean un object que ha transferido la propiedad a su aplicación, y su aplicación es responsable de liberarlo.

De todos modos, si la propiedad se ha transferido a través de un método Core Foundation con Copy o Create en el nombre, puede liberarla manualmente con CFRelease cuando CFRelease con él, o, más fácil, puede transferir la propiedad a ARC y dejar que se tome preocuperase por ello. Históricamente, para transferir la propiedad a ARC, usamos __bridge_transfer , pero ahora recomiendan CFBridgingRelease (aunque este último solo es una macro para el primero). Y, obviamente, si tiene algún object Core Foundation que haya recuperado mediante algún otro mecanismo que no sea una function con Copy o Create en el nombre, no debería CFRelease ni transferir la propiedad a ARC.

A modo de ilustración, este método cumple lo que desea:

 + (NSString *) fileExtensionForMimeType:(NSString *)type { NSString *uti = CFBridgingRelease(UTTypeCreatePrefernetworkingIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)type, NULL)); return CFBridgingRelease(UTTypeCopyPrefernetworkingTagWithClass((__bridge CFStringRef)uti, kUTTagClassFilenameExtension)); } 

En términos generales, creo que debería tratar de comentar la primera línea CFRelease (mimeType) y descomentar las dos líneas siguientes: CFRelease (uti) y CFRelease (extensión). Lanzas un puente sin cargo para ingresar a NSString y ARC se encargará de la versión. Pero el uti y la extensión se crean / copyn como CFString. ARC no sabrá cómo manejarlos (recuerde que ARC es una característica del comstackdor para NSObject), por lo que necesita que CF los libere.