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 destinationT
. SiT
est un type de pointeur d'objet à conserver, alorsop
doit avoir un type de pointeur non à conserver. SiT
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 CGColorRef
s. Je suppose que je devrais utiliser __brige
ici, mais la raison pour laquelle je devrais (ou ne devrais pas) n’est pas claire.
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.
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
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.