web-dev-qa-db-fra.com

ARC et fonte pontée

Avec ARC, je ne peux plus convertir CGColorRef en id. J'ai appris que je devais faire une distribution pontée. Selon clang docs :

Une distribution pontée est une diffusion de style C annotée avec l'un des trois mots clés suivants:

(__bridge T) op lance l'opérande sur le type de destination T. Si T est un type de pointeur d'objet à conserver, alors op doit avoir un type de pointeur non à conserver. Si T est un type de pointeur non conservable, op doit alors posséder un type de pointeur d'objet à conserver. Sinon, le casting est mal formé. Il n'y a pas de transfert de propriété et ARC n'insère aucune opération de conservation.

(__bridge_retained T) op convertit l'opérande, qui doit avoir un type de pointeur d'objet à conserver, vers le type de destination, qui doit être un type de pointeur non à conserver. ARC conserve la valeur, sous réserve des optimisations habituelles sur les valeurs locales, et le destinataire est responsable de l'équilibrage de ce +1.

(__bridge_transfer T) op convertit l'opérande, qui doit avoir un type de pointeur non conservable, vers le type de destination, qui doit être un type de pointeur d'objet à conserver. ARC publiera la valeur à la fin de l'expression complète englobante, sous réserve des optimisations habituelles sur les valeurs locales.

Ces conversions sont nécessaires pour transférer des objets dans et hors du contrôle ARC; voir la justification dans la section sur la conversion des pointeurs d'objet à conserver.

Utilisant un __bridge_retained ou __bridge_transfer _ lancer uniquement pour convaincre ARC d'émettre une rétention ou une libération déséquilibrée, respectivement, est de forme médiocre.

Dans quel genre de situations utiliserais-je chacun?

Par exemple, CAGradientLayer a une propriété colors qui accepte un tableau de CGColorRefs. Je suppose que je devrais utiliser __brige ici, mais la raison pour laquelle je devrais (ou ne devrais pas) n’est pas claire.

163
Morrowless

Je conviens que la description est déroutante. Comme je viens de les saisir, je vais essayer de résumer:

  • (__bridge_transfer <NSType>) op Ou CFBridgingRelease(op) est utilisé pour utiliser le nombre de retenues d'un CFTypeRef lors de son transfert vers ARC. Cela pourrait aussi être représenté par id someObj = (__bridge <NSType>) op; CFRelease(op);

  • (__bridge_retained <CFType>) op Ou CFBridgingRetain(op) est utilisé pour remettre un NSObject à CF-land tout en lui attribuant un nombre de retenues égal à +1. Vous devez gérer un CFTypeRef que vous créez de cette manière de la même manière que vous manipuleriez un résultat de CFStringCreateCopy(). Cela pourrait aussi être représenté par CFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;

  • __bridge Jette juste entre pointeur-terre et Objective-C. Si vous n’avez aucune envie d’utiliser les conversions ci-dessus, utilisez celle-ci.

Peut-être que cela est utile. Moi-même, je préfère les macros CFBridging… Plutôt que les versions normales.

215
monkeydom

J'ai trouvé une autre explication dans la documentation iOS qui, à mon avis, est plus facile à comprendre:

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

  • __bridge_retained (CFBridgingRetain) lance un pointeur Objective-C vers un pointeur Core Foundation et vous en transfère également la propriété.

    Vous êtes responsable d'avoir appelé CFRelease ou une fonction associée pour renoncer à la propriété de l'objet.

  • __bridge_transfer (CFBridgingRelease) déplace un non-Objective-C pointeur vers Objective-C et transfère également la propriété à ARC.

    ARC est responsable de renoncer à la propriété de l'objet.

Source: Types de ponts sans frais

53
gregschlom

Par la suite, dans ce cas particulier, si vous êtes sur iOS, Apple recommande d'utiliser UIColor et ses -CGColor méthode pour retourner le CGColorRef dans le colors NSArray. Dans le Notes de version de transition vers ARC , sous la section "Le compilateur traite les objets CF renvoyés à partir de méthodes Cocoa", il est indiqué que l'utilisation d'une méthode telle que -CGColor qui renvoie un objet Core Foundation sera automatiquement géré correctement par le compilateur.

Ainsi, ils suggèrent d'utiliser le code suivant:

CAGradientLayer *gradientLayer = (CAGradientLayer *)[self layer];
gradientLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor],
                                                 (id)[[UIColor lightGrayColor] CGColor], nil];

Notez qu'à l'heure actuelle, l'exemple de code d'Apple ne contient pas la conversion (id) ci-dessus, ce qui est toujours nécessaire pour éviter une erreur du compilateur.

32
Brad Larson