I'm trying to convert my old project to ARC. I have a function which creates UUIDs, but apparently this is no longer supported when using ARC:
NSString *uuid = nil;
CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault);
if (theUUID) {
uuid = NSMakeCollectable(CFUUIDCreateString(kCFAllocatorDefault, theUUID));
//[uuid autorelease];
CFRelease(theUUID);
}
I get the compiler error (when trying to convert): 'NSMakeCollectable' is unavailable: not available in automatic reference counting mode.
So my question is: how do I create UUIDs when using ARC? Is there another way which I should now use?
NSMakeCollectable()
is for the benefit of the (essentially deprecated) Objective-C garbage collector. ARC knows nothing about it.
You must use a special casting attribute, usually __bridge_transfer
, to ensure that the memory is not leaked. __bridge_transfer
is used like so:
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;
}
Edit: As other answers have mentioned, CFBridgingRelease()
does this for you. So instead of using (__bridge_transfer id)uuid
, it may be cleaner to write CFBridgingRelease(uuid)
. They are equivalent though, so it's up to you which you find more readable.
When you transfer the object from CFString
to NSString
, you need to let ARC know how you want to handle memory management. In this case I would suggest:
uuid = CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, theUUID));
This instructs CoreFoundation to release the object (as is required to balance Create
). Cocoa will ARC-retain the object when it is assigned to uuid
.
CFUUIDRef theUUID = CFUUIDCreate(NULL);
NSString *s2ndUuid = (__bridge_transfer NSString*)CFUUIDCreateString(kCFAllocatorDefault, theUUID);
To have a single UUID across whole app, I think the best way to achieve that would be to have it run once in the whole application lifecycle.
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;
}
it's definition of NSMakeCollectable
NS_INLINE id NSMakeCollectable(CFTypeRef cf) {
return cf ? (id)CFMakeCollectable(cf) : nil;
}
I think this should work
uuid =CFUUIDCreateString(kCFAllocatorDefault, theUUID);