2012-10-06 25 views
5

Estoy intentando una prueba simple para un proyecto mucho más complejo, pero estoy desconcertado de por qué el código siguiente se bloquea y da un error EXC_BAD_ACCESS.UIImage de CGImageRef

Esto se llama desde una UIView.

- (void)testing { 
     NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"ball.png" ofType:nil]; 
     CGImageRef imageRef = [[[UIImage alloc]initWithContentsOfFile:imagePath]CGImage]; 
// CGImageRetain(imageRef); 

     UIImage *newImage = [[UIImage alloc]initWithCGImage:imageRef]; 
     UIImageView *iv = [[UIImageView alloc]initWithImage:newImage]; 
     [self addSubview:iv]; 
} 

Mi conjetura es que el CGImageRef no está siendo retenido pero añadiendo CGImageRetain (imageRef); No hace diferencia.

También debería tener en cuenta que este proyecto tiene ARC encendido.

EDITAR

lo hice un poco más pruebas y han descubierto que esto está directamente relacionado con ARC como creé 2 proyectos básicos que incluye sólo el código de seguridad. El primero con ARC apagado y funcionó perfectamente. El siguiente con ARC encendido y BAM se bloquea con el mismo error. Lo interesante es que recibí un error de registro real SOLAMENTE la primera vez que ejecuté el proyecto antes del accidente.

Error: ImageIO: ImageProviderCopyImageBlockSetCallback 'ImageProviderCopyImageBlockSetCallback' header is not a CFDictionary... 

Respuesta

9

Esta línea es el problema:

CGImageRef imageRef = [[[UIImage alloc]initWithContentsOfFile:imagePath]CGImage]; 

La creado UIImage se dará a conocer inmediatamente después de esta completa expresión (por ejemplo, después de esta línea). Así que incluso intentar agregar un CGImageRetain() después no funcionará.

El problema fundamental es la CGImageRef regresar de CGImage es casi seguro que una Ivar de la UIImage y se dará a conocer cuando el UIImage se deallocted.

La forma genérica de solucionar esto es prolongar la vida útil del UIImage. Puede hacer esto colocando el UIImage en una variable local y haciendo referencia a ella después de su última referencia al CGImage (por ejemplo, con (void)uiimageVar). Alternativamente, se puede retener el CGImageRef en esa misma línea, como en

CGImageRef imageRef = CGImageRetain([[[UIImage alloc] initWithContentsOfFile:imagePath] CGImage]); 

Pero si lo hace, no se olvide de liberar el imageRef cuando haya terminado.

5

escribiste esto:

CGImageRef imageRef = [[[UIImage alloc]initWithContentsOfFile:imagePath]CGImage]; 

Eso crea una línea de UIImage, obtiene su propiedad CGImage, y luego se libera el objeto UIImage. Como no conserva el CGImage en esa línea, el único propietario del CGImage es el UIImage. Por lo tanto, cuando se libera el UIImage e inmediatamente se desasigna, también desasigna el CGImage.

Necesita conservar el CGImage antes de que se libere el UIImage. Prueba esto:

CGImageRef imageRef = CGImageRetain([[UIImage alloc]initWithContentsOfFile:imagePath].CGImage); 

y luego, al final de la función:

CGImageRelease(imageRef); 
+0

Fantástico, ahora veo exactamente lo que está pasando. Al menos yo estaba en el camino correcto. Gracias Rob. – EcksMedia