NSString в CFStringRef и CFStringRef в NSString в ARC?

87

Я пытаюсь понять , правильный способ получить NSStringот А CFStringRefв АРК? То же самое для движения в противоположном направлении, CFStringRefкак NSStringв ARC?

Как правильно это сделать, не создавая утечек памяти?

Zumzum
источник
4
CFStringRef foo (__bridge CFStringRef)theNSString;andNSString *bar = (__bridge NSString *)theCFString;
Не могли бы вы подробно объяснить, что происходит на самом деле при использовании этих двух вариантов?
zumzum
Не совсем. Я не использую ARC, поэтому все, что я знаю, это то, что вам нужно это делать, но не почему.
1
@GabrielePetronella ARC должна была упростить кодирование, сделать код короче и читабельнее, а также уменьшить вероятность человеческих ошибок. Итак, теперь вместо того, чтобы заботиться о подсчете ссылок с помощью объектов retaining и release-ing, мы должны теперь использовать «красивые» преобразования типа __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
}

в таком случае вы можете захотеть сохранить 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 включится и освободит память для вас.

С другой стороны, вы можете преобразовать a 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указатель.
Габриэле Петронелла