objective framework developer apple ios objective-c memory-management core-graphics cgpath

ios - framework - Dónde y cómo__bridge



objective c documentation (2)

La documentación sobre el uso de la palabra clave bridge se puede encontrar aquí . Específicamente, quiero señalar §3.2.4:

(__bridge T) op el operando en el 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.

El puntero que le pasan ( void* ) es un tipo de puntero no retenible, mientras que su NSMutableArray es un tipo de puntero retenible. Esto descarta __bridge_retained directamente. ¿Entonces la pregunta es, a __bridge o __bridge_transfer ?

__bridge_transfer se usa normalmente cuando se quiere el puntero de Objective-C desde un método que devuelve un objeto CF que se ha retenido. Por ejemplo, CFStringCreateWithFormat devolverá un CFString retenido, pero si desea un NSString a partir de él, debe __bridge_transfer entre ellos. Esto hará que ARC libere el objeto que retuvo CF cuando sea apropiado. Por ejemplo, NSString* str = (__bridge_transfer NSString*) CFStringCreateWithFormat(...);

Tu código no está haciendo eso, no necesitas interferir con la propiedad. Su método principal está en control de su gestión de memoria, y simplemente está pasando una referencia a un método al que llama (aunque indirectamente, pero está todo dentro del alcance de main). Como tal, __bridge .

Pero espere, cuando uso __bridge, ¿mi código tiene errores de acceso a la memoria?

Ah, este es un problema con el código que publicaste, y no está relacionado con toda la discusión de bridging. Debe pasar un void* a CGApplyPath, para su función de procesamiento _processPathElement . Lo que está pasando es NSMutableArray** .

Cuando NSMutableArray* a NSMutableArray* , en realidad estás lanzando un NSMutableArray** . Esto causará el infame EXC_BAD_ACCESS. Debe pasar el puntero en sí, no un puntero a un puntero. Pero , CGPathApply(path, pathPoints, _processPathElement) no funcionará, no puede pasar un NSMutableArray* como un void* . Lo que necesitas (irónicamente) es un puente. Por las mismas razones que antes, todo lo que necesita es __bridge . Vea a continuación el código, con los puentes correctos en su lugar, y funcionando como se espera:

#import <UIKit/UIKit.h> #import <Foundation/Foundation.h> void _processPathElement(void* info, const CGPathElement* element) { NSMutableArray *array = (__bridge NSMutableArray*) info; switch (element->type) { case kCGPathElementMoveToPoint: case kCGPathElementAddLineToPoint: { CGPoint point = element->points[0]; [array addObject:[NSValue valueWithCGPoint:point]]; break; } default: break; } } int main(int argc, char *argv[]) { @autoreleasepool { //Create path CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint( path, NULL, 0, 0); CGPathAddLineToPoint(path, NULL, 1, 0); CGPathAddLineToPoint(path, NULL, 1, 1); CGPathAddLineToPoint(path, NULL, 0, 1); CGPathCloseSubpath(path); NSMutableArray *pathPoints = [[NSMutableArray alloc] init]; CGPathApply(path, (__bridge void*)pathPoints, _processPathElement); NSLog(@"Points:%@", pathPoints); } }

Esto se imprimirá:

Points:( "NSPoint: {0, 0}", "NSPoint: {1, 0}", "NSPoint: {1, 1}", "NSPoint: {0, 1}" )

Necesito algunos consejos sobre __bridge -ing en iOS.

Con suerte, el SSCCE 1 a continuación explicará el problema mejor que yo en palabras, pero necesito saber cómo puedo convertir un void* a un NSMutableArray* ; qué variación de __bridge debería usarse (Ver comentario en el código).

Leyendo acerca de los diferentes puentes, __bridge_transfer que necesitaría __bridge_transfer pero luego recibo un EXC_BAD_ACCESS en addObject:

En última instancia, me gustaría tener una variedad de CGPoints en CGPath después de que se haya llamado a CGPathApply .

#import <Foundation/Foundation.h> void _processPathElement(void* info, const CGPathElement* element) { NSMutableArray *array = (/* WHAT BRIDGE HERE */ NSMutableArray*) info; switch (element->type) { case kCGPathElementMoveToPoint: case kCGPathElementAddLineToPoint: { CGPoint point = element->points[0]; [array addObject:[NSValue valueWithCGPoint:point]]; break; } default: break; } } int main(int argc, char *argv[]) { @autoreleasepool { //Create path CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint( path, NULL, 0, 0); CGPathAddLineToPoint(path, NULL, 1, 0); CGPathAddLineToPoint(path, NULL, 1, 1); CGPathAddLineToPoint(path, NULL, 0, 1); CGPathCloseSubpath(path); NSMutableArray *pathPoints = [NSMutableArray array]; CGPathApply(path, &pathPoints, _processPathElement); NSLog(@"Points:%@", pathPoints); } }

1: SSCCE


No estoy seguro de por qué funciona esto, pero he encontrado la solución para ser:

NSMutableArray *array = (__bridge NSMutableArray*) info; //AND CGPathApply(path, (__bridge void*)pathPoints, _processPathElement);

Si alguien puede explicar por qué funciona esto y confirmar que no hay (/ hay) ninguna pérdida de memoria, le agradecería