objective c - ARC y reparto puente
objective-c automatic-ref-counting (3)
Como seguimiento, en este caso específico, si tiene iOS, Apple recomienda utilizar UIColor y su método -CGColor
para devolver el CGColorRef a los colors
NSArray. En las Notas de versión de Transitioning to ARC , en la sección "El compilador maneja los objetos de CF devueltos desde métodos de cacao", se indica que el compilador manejará correctamente el uso de un método como -CGColor
que devuelve un objeto de Core Foundation.
Por lo tanto, sugieren usar un código como el siguiente:
CAGradientLayer *gradientLayer = (CAGradientLayer *)[self layer];
gradientLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor],
(id)[[UIColor lightGrayColor] CGColor], nil];
Tenga en cuenta que a partir de ahora, al código de ejemplo de Apple le falta el molde (id) que tengo arriba, que aún es necesario para evitar un error del compilador.
Con ARC, ya no puedo convertir CGColorRef
en id
. Aprendí que necesito hacer un reparto en puente. Según clang docs :
Un elenco en puente es un elenco de estilo C anotado con una de tres palabras clave:
(__bridge T) op
lanza el operando al tipo de destinoT
SiT
es un tipo de puntero de objeto retenible, entoncesop
debe tener un tipo de puntero no retenible. SiT
es un tipo de puntero no retenible, entonces op debe tener un tipo de puntero de objeto retenible. De lo contrario, el yeso está mal formado. No hay transferencia de propiedad, y ARC no inserta operaciones de retención.
(__bridge_retained T) op
lanza el operando, que debe tener un tipo de puntero de objeto retenible, al tipo de destino, que debe ser un tipo de puntero no retenible. ARC conserva el valor, sujeto a las optimizaciones habituales en los valores locales, y el destinatario es responsable de equilibrar ese +1.
(__bridge_transfer T) op
lanza el operando, que debe tener un tipo de puntero no retenible, al tipo de destino, que debe ser un tipo de puntero de objeto retenible. ARC lanzará el valor al final de la expresión completa adjunta, sujeto a las optimizaciones habituales en los valores locales.Estos moldes son necesarios para transferir objetos dentro y fuera del control ARC; ver el razonamiento en la sección sobre conversión de punteros de objetos retenibles.
Usar un
__bridge_retained
o__bridge_transfer
puramente para convencer a ARC de que emita un retener o liberar desequilibrado, respectivamente, es una forma pobre.
¿En qué tipo de situaciones usaría cada uno?
Por ejemplo, CAGradientLayer
tiene una propiedad de colors
que acepta una matriz de CGColorRef
s. Mi suposición es que debería usar __brige
aquí, pero exactamente por qué debería (o no debería) no está claro.
Encontré otra explicación en la documentación de iOS que creo que es más fácil de entender:
__bridge
transfiere un puntero entre Objective-C y Core Foundation sin transferencia de propiedad.__bridge_retained (CFBridgingRetain)
arroja un puntero de Objective-C a un puntero de Core Foundation y también le transfiere la propiedad.Usted es responsable de llamar a CFRelease o una función relacionada para renunciar a la propiedad del objeto.
__bridge_transfer (CFBridgingRelease)
mueve un puntero no-Objective-C a Objective-C y también transfiere la propiedad a ARC.ARC es responsable de renunciar a la propiedad del objeto.
Fuente: Tipos puente sin cargo
Estoy de acuerdo en que la descripción es confusa. Como acabo de entenderlos, intentaré resumir:
(__bridge_transfer <NSType>) op
o alternativamenteCFBridgingRelease(op)
se utiliza para consumir un conteoCFTypeRef
de unCFTypeRef
mientras se transfiere a ARC. Esto también podría ser representado porid someObj = (__bridge <NSType>) op; CFRelease(op);
id someObj = (__bridge <NSType>) op; CFRelease(op);
(__bridge_retained <CFType>) op
o, alternativamente,CFBridgingRetain(op)
se usa paraNSObject
unNSObject
a CF-land mientras le da un +1 retener conteo. Debe manejar unCFTypeRef
que cree de esta manera igual que manejaría un resultado deCFStringCreateCopy()
. Esto también podría ser representado porCFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;
CFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;
__bridge
solo lanza entre puntero-tierra y Objective-C object-land. Si no tiene inclinación para usar las conversiones anteriores, use esta.
Tal vez esto sea útil. Yo prefiero las macros CFBridging…
un poco más que las versiones planas.