NSString vers CFStringRef et CFStringRef vers NSString dans ARC?

87

J'essaie de comprendre la bonne façon d'obtenir un à NSStringpartir d'un CFStringRefARC? Idem pour aller la direction opposée, CFStringRefà NSStringen ARC?

Quelle est la bonne façon de procéder sans créer de fuites de mémoire?

zumzum
la source
4
CFStringRef foo (__bridge CFStringRef)theNSString;etNSString *bar = (__bridge NSString *)theCFString;
Pourriez-vous expliquer en détail ce qui se passe réellement lorsque ces deux options sont utilisées?
zumzum
Pas assez. Je n'utilise pas ARC, donc tout ce que je sais, c'est que vous devez le faire, mais pas le pourquoi.
1
@GabrielePetronella ARC était censé rendre le codage facile, le code plus court et plus lisible et réduire la possibilité d'erreurs humaines. Donc, maintenant, au lieu d'avoir à s'occuper des comptages de références en retaining et release-ing des objets, nous devons maintenant utiliser de "beaux" moulages comme __bridge_transfer, __unsafe_unretainedet __autoreleasing. Personne n'a pas le temps pour ça. (Et sérieusement, c'est plus difficile à lire. À mon avis, cela n'a pas du tout facilité la gestion de la mémoire.)
1
@ H2CO3 merci pour la réponse. Je ne suis pas du tout d'accord, surtout avec la dernière phrase, mais je respecte votre point de vue :)
Gabriele Petronella

Réponses:

177

Typiquement

NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;

et

CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;

Maintenant, si vous voulez savoir pourquoi le __bridgemot-clé est là, vous pouvez vous référer à la documentation Apple . Vous y trouverez:

__bridge transfère un pointeur entre Objective-C et Core Foundation sans transfert de propriété.

__bridge_retainedou CFBridgingRetainjette un pointeur Objective-C vers un pointeur Core Foundation et vous transfère également la propriété. Vous êtes responsable d'appeler CFRelease ou une fonction associée pour renoncer à la propriété de l'objet.

__bridge_transferou CFBridgingReleasedéplace un pointeur non-Objective-C vers Objective-C et transfère également la propriété à l'ARC. ARC est responsable de renoncer à la propriété de l'objet.

Ce qui signifie que dans les cas ci-dessus, vous lancez l'objet sans en changer la propriété. Cela implique que dans aucun des cas, vous ne serez responsable de la gestion de la mémoire des chaînes.

Il se peut également que vous souhaitiez transférer la propriété pour une raison quelconque.

Par exemple, considérez l'extrait suivant

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

dans ce cas, vous souhaiterez peut-être enregistrer un CFReleaseen transférant la propriété lors de la diffusion.

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

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

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

La propriété de stra été transférée, donc maintenant ARC entrera en vigueur et libérera la mémoire pour vous.

À l'inverse, vous pouvez convertir un NSString *en un en CFStringutilisant un __bridge_retainedcast, de sorte que vous possédiez l'objet et que vous deviez le libérer explicitement en utilisant CFRelease.


Pour conclure, vous pouvez avoir

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
la source
Merci beaucoup, ce n'est pas vraiment intuitif, mais grâce à vous, leçon apprise
Sulfkain
@: petite question. donc si nous utilisons ARC. quand NSString->CFString, nous devrions utiliser __bridge. mais quand CFString->NSString, nous devrions utiliser __bride_transfer. ? Et tout effet secondaire, si nous utilisons CFReleasequand nous n'en avons pas besoin trop. merci :)
hqt
@hqt, si vous voulez le moyen «facile», oui ce que vous dites est correct. En outre, un supplément CFReleasedevrait raisonnablement planter votre programme, car vous vous retrouverez avec une opération de conservation / libération incompatible, ce qui finira par libérer un NULLpointeur.
Gabriele Petronella