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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With