NSString para CFStringRef e CFStringRef para NSString em ARC?

87

Estou tentando entender a maneira correta de obter um NSStringde a CFStringRefno ARC. O mesmo para ir na direção oposta, CFStringRefpara NSStringno ARC?

Qual é a maneira correta de fazer isso sem criar vazamentos de memória?

zumzum
fonte
4
CFStringRef foo (__bridge CFStringRef)theNSString;eNSString *bar = (__bridge NSString *)theCFString;
Você poderia explicar o que realmente está acontecendo em detalhes quando essas duas opções são usadas?
zumzum
Não exatamente. Eu não uso ARC, então tudo que sei é que você tem que fazer isso, mas não o porquê.
1
O ARC de @GabrielePetronella deveria tornar a codificação fácil, mais curta e legível e reduzir a possibilidade de erros humanos. Portanto, agora em vez de ter que cuidar das contagens de referência retaining e release-ing objetos, devemos usar moldes "bonitos" como __bridge_transfer, __unsafe_unretainede __autoreleasing. Ninguém não tem tempo para isso. (E,
1
@ H2CO3 obrigado pela resposta. Discordo totalmente, principalmente com a última frase, mas respeito seu ponto de vista :)
Gabriele Petronella

Respostas:

177

Tipicamente

NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;

e

CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;

Agora, se você quiser saber por que a __bridgepalavra-chave está lá, consulte a documentação da Apple . Lá você encontrará:

__bridge transfere um ponteiro entre Objective-C e Core Foundation sem transferência de propriedade.

__bridge_retainedou CFBridgingRetainconverte um ponteiro Objective-C em um ponteiro Core Foundation e também transfere a propriedade para você. Você é responsável por chamar CFRelease ou uma função relacionada para abrir mão da propriedade do objeto.

__bridge_transferou CFBridgingReleasemove um ponteiro não Objective-C para Objective-C e também transfere a propriedade para ARC. A ARC é responsável por renunciar à propriedade do objeto.

O que significa que nos casos acima você está lançando o objeto sem alterar a propriedade. Isso significa que, em nenhum dos casos, você será responsável pelo manuseio da memória das cordas.

Também pode haver o caso em que você deseja transferir a propriedade por algum motivo.

Por exemplo, considere o seguinte snippet

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

em tal caso, você pode querer salvar um CFReleasetransferindo a propriedade ao lançar.

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

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

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

A propriedade de strfoi transferida, então agora o ARC entrará em ação e liberará a memória para você.

Por outro lado, você pode converter um NSString *em um CFStringusando um __bridge_retainedelenco, de modo que você será o proprietário do objeto e terá que liberá-lo explicitamente usando CFRelease.


Para finalizar você pode ter

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;
Gabriele Petronella
fonte
Muito obrigado, isso não é realmente intuitivo, mas graças a você, lição aprendida
Sulfkain
@: pequena pergunta. então, se usarmos ARC. quando NSString->CFString, devemos usar __bridge. mas quando CFString->NSString, devemos usar __bride_transfer. ? E qualquer efeito colateral, se usarmos CFReleasequando não precisarmos também. obrigado :)
hqt
@hqt, se você quer a maneira 'fácil', sim, o que você diz está correto. Além disso, um extra CFReleasedeve travar razoavelmente seu programa, já que você terminará com uma operação de retenção / liberação incompatível, eventualmente liberando um NULLponteiro.
Gabriele Petronella