ARC y reparto puente

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 destino T Si T es un tipo de puntero de objeto retenible, entonces op debe tener un tipo de puntero no retenible. Si T 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.

Estoy de acuerdo en que la descripción es confusa. Como acabo de entenderlos, intentaré resumir:

  • (__bridge_transfer ) op o alternativamente CFBridgingRelease(op) se utiliza para consumir un conteo CFTypeRef de un CFTypeRef mientras se transfiere a ARC. Esto también podría ser representado por id someObj = (__bridge ) op; CFRelease(op); id someObj = (__bridge ) op; CFRelease(op);

  • (__bridge_retained ) op o, alternativamente, CFBridgingRetain(op) se usa para NSObject un NSObject a CF-land mientras le da un +1 retener conteo. Debe manejar un CFTypeRef que cree de esta manera igual que manejaría un resultado de CFStringCreateCopy() . Esto también podría ser representado por CFRetain((__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.

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

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 comstackdor maneja los objetos de CF devueltos desde métodos de cocoa”, se indica que el comstackdor 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 comstackdor.