NSMakeCollectable и ARC не работает - PullRequest
23 голосов
/ 21 декабря 2011

Я пытаюсь преобразовать мой старый проект в ARC. У меня есть функция, которая создает UUID, но, видимо, это больше не поддерживается при использовании ARC:

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

Я получаю сообщение об ошибке компилятора (при попытке преобразования): «NSMakeCollectable» недоступен: недоступен в режиме автоматического подсчета ссылок.

Итак, мой вопрос: как мне создать UUID при использовании ARC? Есть ли другой способ, которым я должен сейчас воспользоваться?

Ответы [ 5 ]

30 голосов
/ 21 декабря 2011

NSMakeCollectable() предназначен для (по существу устаревшего) сборщика мусора Objective-C. ARC ничего не знает об этом.

Вы должны использовать специальный атрибут приведения, обычно __bridge_transfer, чтобы гарантировать, что память не просочилась. __bridge_transfer используется так:

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

Редактировать : Как уже упоминалось в других ответах, CFBridgingRelease() делает это для вас. Таким образом, вместо использования (__bridge_transfer id)uuid, может быть, лучше написать CFBridgingRelease(uuid). Хотя они эквивалентны, так что вам решать, что вы найдете более читабельным.

8 голосов
/ 21 декабря 2011

Когда вы переносите объект из CFString в NSString, вам нужно сообщить ARC, как вы хотите управлять памятью. В этом случае я бы предложил:

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

Это дает CoreFoundation команду освободить объект (как требуется для балансировки Create). Какао будет ARC-сохранить объект, когда ему присвоено uuid.

1 голос
/ 14 ноября 2012

Чтобы иметь единый UUID для всего приложения, я думаю, что лучший способ добиться этого - запустить его один раз за весь жизненный цикл приложения.

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;
}
1 голос
/ 01 августа 2012
CFUUIDRef theUUID = CFUUIDCreate(NULL);

NSString *s2ndUuid = (__bridge_transfer NSString*)CFUUIDCreateString(kCFAllocatorDefault, theUUID);
0 голосов
/ 21 декабря 2011

это определение NSMakeCollectable

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

Я думаю, что это должно работать

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