lanzamiento - ios 12 iphone 6
Desarrollo de iPhone: el puntero que se está liberando no fue asignado (7)
He luchado con el mismo error en mi código. Lo que me desconcertó es que mi aplicación funcionó en OS 3.0 sin ningún problema hasta que hice una pequeña modificación en un código que no tiene nada que ver con las cosas de CGImage *. Pero una vez que comenzó a fallar, entonces nunca funcionó sin estrellarse. Cuando cambié a 3.1, todo funcionó de nuevo. Reduje el error a una llamada CGImageRelease (). Quitar esa línea o agregar una retención en el UIImage resultante resolvió el problema, aunque esto no es una solución ya que la aplicación perderá memoria.
Intenté usar NSZombie con instrumentos. Esto no ayudó, la aplicación se estrelló sin que se detectara ningún zombi.
Además, las aplicaciones de ejemplo de Apple (como TheElements) NO se bloquean, pero utilizan el mismo código EXACTO que mi aplicación. Entonces, estoy luchando para aceptar que el problema está en los marcos. Por ahora, voy a cambiar a 3.1 y seguir adelante.
Recibí este mensaje del depurador:
Pixture(1257,0xa0610500) malloc: *** error for object 0x21a8000: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Así que hice un poco de rastreo y obtuve:
(gdb) shell malloc_history 1257 0x21a8000
ALLOC 0x2196a00-0x21a89ff [size=73728]: thread_a0610500 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopDoObservers | CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) | CA::Transaction::commit() | CA::Context::commit_transaction(CA::Transaction*) | CALayerDisplayIfNeeded | -[CALayer _display] | CABackingStoreUpdate | backing_callback(CGContext*, void*) | -[CALayer drawInContext:] | -[UIView(CALayerDelegate) drawLayer:inContext:] | -[AvatarView drawRect:] | -[AvatarView overlayPNG:] | +[UIImageUtility createMaskOf:] | UIGraphicsGetImageFromCurrentImageContext | CGBitmapContextCreateImage | create_bitmap_data_provider | malloc | malloc_zone_malloc
y realmente no puedo entender lo que estoy haciendo mal. Aquí está el código de la función [UIImageUtility createMaskOf:]
:
+ (UIImage *)createMaskOf:(UIImage *)source {
CGRect rect = CGRectMake(0, 0, source.size.width, source.size.height);
UIGraphicsBeginImageContext(CGSizeMake(source.size.width, source.size.height));
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, source.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
UIImage *original = [self createGrayCopy:source];
CGContextRef context2 = CGBitmapContextCreate(NULL, source.size.width, source.size.height, 8, 4 * source.size.width,
CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipLast);
CGContextDrawImage(context2, CGRectMake(0, 0, source.size.width, source.size.height), original.CGImage);
CGImageRef unmasked = CGBitmapContextCreateImage(context2);
const float myMaskingColorsFrameColor[6] = { 1,256,1,256,1,256 };
CGImageRef mask = CGImageCreateWithMaskingColors(unmasked, myMaskingColorsFrameColor);
CGContextSetRGBFillColor (context, 256,256,256, 1);
CGContextFillRect(context, rect);
CGContextDrawImage(context, rect, mask);
UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return whiteMasked;
}
la otra función personalizada llamada antes es la siguiente:
- (UIImage *)overlayPNG:(SinglePart *)sp {
NSLog([sp description]);
// Rect and context setup
CGRect rect = CGRectMake(0, 0, sp.image.size.width, sp.image.size.height);
NSLog(@"%f x %f", sp.image.size.width, sp.image.size.height);
// Create an image of a color filled rectangle
UIImage *baseColor = nil;
if (sp.hasOwnColor) {
baseColor = [UIImageUtility imageWithRect:rect ofColor:sp.color];
} else {
SinglePart *facePart = [editingAvatar.face.partList objectAtIndex:0];
baseColor = [UIImageUtility imageWithRect:rect ofColor:facePart.color];
}
// Crete the mask of the layer
UIImage *mask = [UIImageUtility createMaskOf:sp.image];
mask = [UIImageUtility createGrayCopy:mask];
// Create a new context for merging the overlay and a mask of the layer
UIGraphicsBeginImageContext(CGSizeMake(sp.image.size.width, sp.image.size.height));
CGContextRef context2 = UIGraphicsGetCurrentContext();
// Adjust the coordinate system so that the origin
// is in the lower left corner of the view and the
// y axis points up
CGContextTranslateCTM(context2, 0, sp.image.size.height);
CGContextScaleCTM(context2, 1.0, -1.0);
// Create masked overlay color layer
CGImageRef MaskedImage = CGImageCreateWithMask (baseColor.CGImage, mask.CGImage);
// Draw the base color layer
CGContextDrawImage(context2, rect, MaskedImage);
// Get the result of the masking
UIImage* overlayMasked = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIGraphicsBeginImageContext(CGSizeMake(sp.image.size.width, sp.image.size.height));
CGContextRef context = UIGraphicsGetCurrentContext();
// Adjust the coordinate system so that the origin
// is in the lower left corner of the view and the
// y axis points up
CGContextTranslateCTM(context, 0, sp.image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// Get the result of the blending of the masked overlay and the base image
CGContextDrawImage(context, rect, overlayMasked.CGImage);
// Set the blend mode for the next drawn image
CGContextSetBlendMode(context, kCGBlendModeOverlay);
// Component image drawn
CGContextDrawImage(context, rect, sp.image.CGImage);
UIImage* blendedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRelease(MaskedImage);
return blendedImage;
}
He tenido el mismo problema, con muchos de los mismos síntomas:
- el puntero que se liberó no se asignó error
- actualizado a Xcode 3.2
- error que ocurre en el código de las imágenes
Si cambio el objetivo de compilación a 3.1, los errores en el simulador desaparecen. Si ejecuto el código en el dispositivo, los errores no aparecen. Posiblemente un error en 3.0
Mi consejo es probar con 3.1 como objetivo, y si lo desea, puede compilarlo con 3.0 para el lanzamiento y no preocuparse por los errores, ya que no ocurren en el dispositivo.
Parece que tienes un error de memoria dañada y probablemente no esté en este código. Los errores de memoria dañados son mis segundos errores más divertidos, en parte porque a menudo no son deterministas, y los síntomas (también conocidos como bloqueos) suelen ocurrir mucho después del error real.
Hay dos tipos principales de errores de memoria:
- Asignar más de lo que usted libre.
- Liberar más de lo que asignas.
En este caso, parece que estás liberando demasiado, lo que es el caso más fácil de ver (b / c puede fallar antes) pero es más difícil de localizar.
Aquí hay una estrategia que puede usar para ayudar a encontrar una desasignación adicional:
- Desactiva algunas de tus desasignaciones.
- A ver si el accidente sigue ocurriendo.
Idealmente, puede encontrar un solo comando de desasignación que, cuando se elimine, permitirá que su código funcione correctamente. Podría ser útil probar un enfoque de búsqueda binaria, si eso es práctico para su base de código. Si se trata de una base de código grande, es de esperar que esté usando el control de versiones y pueda intentar concentrarse en las diferencias recientes.
Tenga en cuenta que aquí se pueden invocar desasignaciones de varias maneras diferentes. Lo más probable es que estés llamando release
y autorelease
en objetos. También es posible que esté llamando explícitamente a dealloc
(aunque, por lo general, es un error). Y, por supuesto, puedes incluso llamar explícitamente free
directamente.
Una vez que se haya deshecho de las desasignaciones adicionales, es una buena idea también verificar si hay pérdidas de memoria (es decir, asignaciones adicionales). Puedes hacer esto usando instrumentos y otras herramientas. Un buen punto de partida es leer Cómo encontrar pérdidas de memoria en la guía de desarrollo del iPhone.
Agregado: también es una buena idea establecer un puntero a nil
justo después de haberlo soltado y haber terminado de usarlo. De esta manera, si usted llama [objectPtr release];
más tarde, no hará nada.
(PS Btw, mi tipo de error más divertido # 1 es la corrupción de la memoria en el código mutlithreaded. Una vez tuve uno de esos en una base de código de líneas multimillonaria).
Podría ser solo yo pero no puedes hacer lo siguiente?
UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return whiteMasked;
¿whiteMasked se asigna en la pila de la función y después de que devuelve el puntero ya no es válido? ¿O me estoy perdiendo algo? Si utiliza el UIImage * devuelto, no se garantiza que siga estando allí. (Sería un éxito). ¿No es necesario que asigne un UIImage * y luego lo libere automáticamente antes de regresar?
Si bien es probable que no sea la causa de su bloqueo, está perdiendo memoria al no liberar el context2
, unmasked
y mask
objetos de Core Foundation mediante CFRelease()
, CFImageRelease()
o similares.
Solo quería confirmar, una vez más, que estaba obteniendo:
el puntero liberado no fue asignado
error y desapareció si cambio mi sistema operativo de destino a 3.1 en lugar de 3.0
Tuve el mismo problema con el siguiente código.
-(void)adjustImageToImageView:(UIImage*)img{
float numPixels = 100;
float radius = 5;
UIGraphicsBeginImageContext(CGSizeMake(numPixels, numPixels));
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextBeginPath(c);
CGContextMoveToPoint (c, numPixels, numPixels/2);
CGContextAddArcToPoint(c, numPixels, numPixels, numPixels/2, numPixels, radius);
CGContextAddArcToPoint(c, 0, numPixels, 0, numPixels/2, radius);
CGContextAddArcToPoint(c, 0, 0, numPixels/2, 0, radius);
CGContextAddArcToPoint(c, numPixels, 0, numPixels, numPixels/2, radius);
CGContextClosePath(c);
CGContextClip(c);
[img drawAtPoint:CGPointZero];
UIImage *converted = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.imageView.image = converted; }
Tomé la función de la aplicación de fuente abierta Twitterfon.
Cuando intentaba solucionar el problema, intenté cambiar la última línea a
self.imageView.image = [converted retain]
Y eso detuvo los mensajes de error en la consola. Voy a revisar esto en Fugas pronto para ver qué está pasando.