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) oplanza el operando al tipo de destinoTSiTes un tipo de puntero de objeto retenible, entoncesopdebe tener un tipo de puntero no retenible. SiTes 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) oplanza 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) oplanza 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_retainedo__bridge_transferpuramente 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:
__bridgetransfiere 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>) opo alternativamenteCFBridgingRelease(op)se utiliza para consumir un conteoCFTypeRefde unCFTypeRefmientras 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>) opo, alternativamente,CFBridgingRetain(op)se usa paraNSObjectunNSObjecta CF-land mientras le da un +1 retener conteo. Debe manejar unCFTypeRefque 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;__bridgesolo 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.