web-dev-qa-db-fra.com

NSString à CFStringRef et CFStringRef à NSString dans ARC?

J'essaie de comprendre la manière correcte d'obtenir un NSString à partir d'un CFStringRef dans ARC? Pareil pour aller dans la direction opposée, CFStringRef à NSString dans ARC?

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

79
zumzum

Typiquement

NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;

et

CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;

Maintenant, si vous voulez savoir pourquoi le __bridge Le mot-clé _ est là, vous pouvez vous référer au documentation Apple . Vous y trouverez:

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

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

__bridge_transfer _ ou CFBridgingRelease déplace un pointeur non Objective-C sur Objective-C et transfère la propriété à ARC. ARC est responsable de la renonciation à la propriété de l'objet.

Ce qui signifie que dans les cas ci-dessus, vous lancez l'objet sans en changer le propriétaire. Cela implique que vous ne serez en aucun cas chargé de gérer 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érons 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 un tel cas, vous voudrez peut-être sauvegarder un CFRelease en transférant la propriété lors du casting.

- (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 str a été transférée. ARC lancera et libèrera la mémoire pour vous.

Au contraire, vous pouvez lancer un NSString * à un CFString en utilisant un __bridge_retained cast, pour 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;
163