NSMakeCollectable и ARC не работают
Я пытаюсь преобразовать свой старый проект в ARC. У меня есть функция, которая создает UUID, но, видимо, это больше не поддерживается при использовании ARC:
NSString *uuid = nil;
CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault);
if (theUUID) {
uuid = NSMakeCollectable(CFUUIDCreateString(kCFAllocatorDefault, theUUID));
//[uuid autorelease];
CFRelease(theUUID);
}
Я получаю ошибку компилятора (при попытке конвертировать): "NSMakeCollectable" недоступен: недоступен в режиме автоматического подсчета ссылок.
Итак, мой вопрос: как мне создать UUID при использовании ARC? Есть ли другой способ, который я должен использовать?
Ответы
Ответ 1
NSMakeCollectable()
предназначен для использования (существенно устаревшего) сборщика мусора Objective-C. ARC ничего не знает об этом.
Вы должны использовать специальный атрибут casting, обычно __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 control to ARC control.
}
return result;
}
Изменить. Как уже упоминалось в других ответах, CFBridgingRelease()
делает это для вас. Поэтому вместо использования (__bridge_transfer id)uuid
может быть более чистым писать CFBridgingRelease(uuid)
. Они эквивалентны, так что это зависит от вас, что вы найдете более читаемым.
Ответ 2
Когда вы переносите объект с CFString
на NSString
, вы должны позволить ARC знать, как вы хотите обрабатывать управление памятью. В этом случае я бы предложил:
uuid = CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, theUUID));
Это дает команду CoreFoundation освободить объект (как требуется для балансировки Create
). Cocoa будет ARC-сохранить объект, когда он назначен uuid
.
Ответ 3
CFUUIDRef theUUID = CFUUIDCreate(NULL);
NSString *s2ndUuid = (__bridge_transfer NSString*)CFUUIDCreateString(kCFAllocatorDefault, theUUID);
Ответ 4
Чтобы иметь единственный 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;
}
Ответ 5
это определение NSMakeCollectable
NS_INLINE id NSMakeCollectable(CFTypeRef cf) {
return cf ? (id)CFMakeCollectable(cf) : nil;
}
Я думаю, что это должно работать
uuid =CFUUIDCreateString(kCFAllocatorDefault, theUUID);