NSString для CFStringRef и CFStringRef для NSString в ARC?

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

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

Ответ 1

Как правило

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 начнет использовать и освободит память для вас.

С другой стороны, вы можете использовать NSString * для 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 now in charge of releasing the string object. You won't have to explicitly call `CFRelease` on `str`
NSString *string = (__bridge_transfer NSString *)str;