2011-12-21 17 views
23

Estoy intentando convertir mi antiguo proyecto a ARC. Tengo una función que crea UUID, pero parece que esto ya no se admite cuando se utiliza ARC:NSMakeCollectable y ARC no funciona

NSString *uuid = nil; 
    CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault); 
    if (theUUID) { 
     uuid = NSMakeCollectable(CFUUIDCreateString(kCFAllocatorDefault, theUUID)); 
     //[uuid autorelease]; 
     CFRelease(theUUID); 
    } 

consigo el error del compilador (al intentar convertir): 'NSMakeCollectable' no está disponible: No disponible en el recuento de referencias automática modo.

Entonces mi pregunta es: ¿cómo creo UUID cuando uso ARC? ¿Hay alguna otra manera que ahora debería usar?

Respuesta

30

NSMakeCollectable() es para el beneficio del recolector de basura Objective-C (esencialmente obsoleto). ARC no sabe nada al respecto.

Debe usar un atributo de fundición especial, generalmente __bridge_transfer, para asegurarse de que la memoria no se escape. __bridge_transfer se utiliza de esta manera:

id MakeUUID(void) { 
    id result = nil; 
    CFUUIDRef uuid = CFUUIDCreate(NULL); 
    if (uuid) { 
     result = (__bridge_transfer id)uuid; // this "transfers" a retain from CF's control to ARC's control. 
    } 
    return result; 
} 

Editar: Como han mencionado otras respuestas, CFBridgingRelease() lo hace por usted. Entonces, en lugar de usar (__bridge_transfer id)uuid, puede ser más limpio escribir CFBridgingRelease(uuid). Sin embargo, son equivalentes, por lo que depende de usted que le resulte más legible.

-2

es definición de NSMakeCollectable

NS_INLINE id NSMakeCollectable(CFTypeRef cf) { 
    return cf ? (id)CFMakeCollectable(cf) : nil; 
} 

Creo que esto debería funcionar

uuid =CFUUIDCreateString(kCFAllocatorDefault, theUUID); 
+0

Esto perderá UUID ya que tiene un 'CFRetain' extra adjunto a la llamada' Create'. –

+0

puede usar CFRelease para liberar – IPaPa

+1

CF¿Por qué? Lo has asignado a un 'id' de ARC, que ya no se puede entregar directamente a' CFRelease() '. Podrías lanzarlo de nuevo, pero eso es luchar contra ARC. Esto es a lo que 'CFBridgingRelease()' y su equivalente '__bridge_transfer' están diseñados para abordar. –

8

Al transferir el objeto desde CFString a NSString, es necesario dejar que ARC sabe cómo quiere manejar la gestión de memoria . En este caso yo sugeriría:

uuid = CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, theUUID)); 

Esto indica CoreFoundation para liberar el objeto (como se requiere para equilibrar Create). Cocoa retendrá el objeto cuando esté asignado al uuid.

1
CFUUIDRef theUUID = CFUUIDCreate(NULL); 

NSString *s2ndUuid = (__bridge_transfer NSString*)CFUUIDCreateString(kCFAllocatorDefault, theUUID); 
1

tener un único UUID través de aplicación general, creo que la mejor manera de lograr eso sería para que se ejecute una vez en todo el ciclo de vida de la aplicación.

static NSString *uuid; 
- (NSString *)theCurrentDeviceUniqueIdentifier { 

    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault); 
     if (theUUID) { 
      uuid = CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, theUUID)); 
      CFRelease(theUUID); 
     } 
    }); 

    return uuid; 
}