NSString до CFStringRef і CFStringRef до NSString в ARC?


87

Я намагаюся зрозуміти правильний спосіб отримання повідомлення NSStringз CFStringRefARC? Те саме для руху в зворотному напрямку, CFStringRefдо NSStringARC?

Який правильний спосіб це зробити, не створюючи витоків пам'яті?


4
CFStringRef foo (__bridge CFStringRef)theNSString;andNSString *bar = (__bridge NSString *)theCFString;

Не могли б ви детально пояснити, що насправді відбувається, коли використовуються ці два варіанти?
zumzum

Не зовсім. Я не використовую ARC, тому все, що я знаю, це те, що ви повинні це робити, але не чому.

1
@GabrielePetronella ARC повинен був зробити кодування простим, коротшим та зручнішим для читання та зменшити можливість помилок. Отже, тепер, замість того, щоб піклуватися про підрахунок посилань за допомогою введення retainта releaseдодавання об’єктів, ми тепер повинні використовувати "красиві" відливки типу __bridge_transfer, __unsafe_unretainedта __autoreleasing. Ніхто не має часу на це. (А якщо серйозно, це важче для читання. На мій погляд, це зовсім не полегшило управління пам’яттю.)

1
@ H2CO3 дякую за відповідь. Я категорично не погоджуюсь, особливо з останнім реченням, але я поважаю вашу точку зору :)
Габріеле Петронелла

Відповіді:


177

Зазвичай

NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;

і

CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;

Тепер, якщо ви хочете дізнатися, чому саме __bridgeключове слово, ви можете звернутися до документації Apple . Там ви знайдете:

__bridge передає покажчик між Objective-C та Core Foundation без передачі права власності.

__bridge_retainedабо CFBridgingRetainпередає покажчик Objective-C на покажчик Core Foundation, а також передає вам право власності. Ви несете відповідальність за виклик CFRelease або пов’язаної функції для відмови від права власності на об’єкт.

__bridge_transferабо CFBridgingReleaseпереміщує вказівник, що не є Objective-C, на Objective-C, а також передає право власності ARC. ARC відповідає за відмову від права власності на об'єкт.

Це означає, що у вищезазначених випадках ви кидаєте об’єкт без зміни власника. Це означає, що в жодному випадку ви не будете відповідальні за обробку пам'яті рядків.

Також може бути випадок, коли з якихось причин ви хочете передати право власності.

Наприклад, розглянемо такий фрагмент

- (void)sayHi {
    CFStringRef str = CFStringCreateWithCString(NULL, "Hello World!", kCFStringEncodingMacRoman);

    NSString * aNSString = (__bridge NSString *)str;

    NSLog(@"%@", aNSString);

    CFRelease(str); //you have to release the string because you created it with a 'Create' CF function
}

у такому випадку ви можете захотіти зберегти a CFRelease, передавши право власності під час кастингу.

- (void)sayHi {
    CFStringRef str = CFStringCreateWithCString(NULL, "Hello World!", kCFStringEncodingMacRoman);

    NSString * aNSString = (__bridge_transfer NSString *)str;
// or alternatively
    NSString * aNSString = (NSString *)CFBridgingRelease(str);

    NSLog(@"%@", aNSString);
}

Право власності на strпередано, тож тепер ARC розпочне і звільнить пам’ять для вас.

Навпаки, ви можете NSString *передати a на CFStringза допомогою __bridge_retainedгіста, так що ви будете власником об'єкта, і вам доведеться явно звільнити його за допомогою CFRelease.


Завершити це можна

NSString → CFString

// Don't transfer ownership. You won't have to call `CFRelease`
CFStringRef str = (__bridge CFStringRef)string;

// Transfer ownership (i.e. get ARC out of the way). The object is now yours and you must call `CFRelease` when you're done with it
CFStringRef str = (__bridge_retained CFStringRef)string // you will have to call `CFRelease`

CFString → NSString

// Don't transfer ownership. ARC stays out of the way, and you must call `CFRelease` on `str` if appropriate (depending on how the `CFString` was created)
NSString *string = (__bridge NSString *)str;

// Transfer ownership to ARC. ARC kicks in and it's now in charge of releasing the string object. You won't have to explicitly call `CFRelease` on `str`
NSString *string = (__bridge_transfer NSString *)str;

Велике спасибі, це насправді не інтуїтивно, але завдяки вам, урок
Сульфкейн

@: маленьке запитання. так що якщо ми використовуємо ARC. коли NSString->CFString, ми повинні використовувати __bridge. але коли CFString->NSString, ми повинні використовувати __bride_transfer. ? І будь-який побічний ефект, якщо ми використовуємо, CFReleaseколи нам теж не потрібно. спасибі :)
hqt

@hqt, якщо ти хочеш "простий" спосіб, так, те, що ти кажеш, є правильним. Крім того, додаткова особа CFReleaseповинна розумно розбити вашу програму, оскільки у вас закінчиться невідповідна операція збереження / вивільнення, в кінцевому підсумку випустивши NULLпокажчик.
Габріеле Петронелла
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.