简体   繁体   中英

NSMakeCollectable and ARC doesn't work

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM