objective c - La asignación de un CGColor existente a una propiedad CGColor funciona en iOS Simulator, no en un dispositivo iOS. ¿Por qué?
objective-c ipad (3)
Sé cómo solucionar el problema que estoy a punto de delinear, sin embargo, estoy un poco desconcertado sobre por qué el escenario de código funciona en el simulador de iOS pero no en mi iPad.
Tengo un método que verifica varias propiedades y luego establece el color de fondo de un CALayer
dependiendo del estado de una propiedad. El siguiente código es similar a mi método de asignación de color:
//This will be the CALayer BGColor...
CGColor c = UIColor.blueColor.CGColor; //Blue is the default
switch (myState)
{
case state_one:
c = UIColor.greenColor.CGColor;
//... more code ...
break;
case state_two:
c = UIColor.redColor.CGColor;
//... more code ...
break;
case state_three: //multiple cases are like the state_three case.
//Other code, but I don''t need to assign the color. Blue works...
}
myCALayer.backgroundColor = c; //Oh-noes!!! Here we get the dreaded EXC_BAD_ACCESS on iPad
//...more code dealing with the layer.
El código anterior funciona sin problemas en el simulador. Sin embargo, cuando ejecuto la aplicación en mi iPad, se bloquea en la asignación backgroundColor
.
Puedo solucionar esto deshaciéndome de la variable CGColor
y asignando el color de fondo directamente en mi declaración switch / case, y eso es lo que planeo hacer.
Sin embargo, tengo curiosidad. ¿Por qué esto funcionaría en un entorno y no en el otro?
ACTUALIZAR
Un par de cosas. En primer lugar, vale la pena mencionar que este es un proyecto ARC, que utiliza Xcode 4.2, dirigido a dispositivos iOS 5. Además, mi código de asignación de color no es exactamente lo que parece porque tengo una serie de definiciones que utilizo para establecer estos colores porque se mencionan en toda mi aplicación.
A esto se refieren algunas de las declaraciones #define
:
#define BLUE [UIColor colorWithRed:8.0/255.0 green:80.0/255.0 blue:150.0/255.0 alpha:1.0].CGColor
#define GREEN (UIColor.blueColor.CGColor)
//...and there are about 6 other colors
Traté de simplificar mi código porque el compilador debería reemplazar los refs por mis referencias a mis definiciones. Aún así, vale la pena mencionarlo por las dudas.
Debido a ARC, el color se libera demasiado temprano al final del método.
Yo uso: CGColorRetain
CGColorRef whiteColor = CGColorRetain([UIColor colorWithRed:1.0 green:1.0
blue:1.0 alpha:1.0].CGColor);
Aquí está mi corazonada: es posible que el UIColor
que lo creó (y que tuvo su única referencia) haya sido destruido antes de pasar el CGColor
. Como el CGColorRef
de referencias de CGColorRef
no se maneja bajo ARC, el color sería una referencia que UIColor
si el UIColor
que lo contenía se destruyera antes de utilizar el CGColor
.
ARC tiene una optimización en la que los objetos "liberados automáticamente" nunca se pueden agregar a un grupo de autorrelease, y en su lugar, se released
vez que el objeto objc ya no se referencia. Esta es una combinación de tres cosas:
- La versión del compilador y las opciones que usa. No es de extrañar, el compilador agrega el recuento de referencias, y hay variaciones para esto.
- El tiempo de ejecución ObjC. El tiempo de ejecución puede utilizar datos locales de subprocesos. Naturalmente, esto puede incluir tu stack. Si lees los detalles de cómo un objeto puede eludir un grupo de autorrelease, esto debería ser más claro.
- Las bibliotecas que usa (incluidas las bibliotecas del sistema y los marcos). A medida que se actualizan el compilador y los tiempos de ejecución, las bibliotecas pueden usar ARC, o pueden usar diferentes llamadas en tiempo de ejecución para ejecutar el programa.
Sabiendo eso, sospecho que este programa rectificaría el problema:
UIColor * c = UIColor.blueColor; //Blue is the default
switch (myState) {
case state_one:
c = UIColor.greenColor;
//... more code ...
break;
case state_two:
c = UIColor.redColor;
//... more code ...
break;
case state_three: //multiple cases are like the state_three case.
//Other code, but I don''t need to assign the color. Blue works...
}
myCGLayer.backgroundColor = c.CGColor;
//...more code dealing with the layer.
En más detalle, hay varias maneras en que el compilador y el tiempo de ejecución objc pueden interpretar y ejecutar su programa. Esto significa que este problema podría afectarlo cuando cambie las versiones del compilador o cuando se actualice el tiempo de ejecución (SO). También puede ocurrir porque las bibliotecas que usa se actualizan o compilan con diferentes versiones o configuraciones de compilador. Por ejemplo: si la biblioteca cambia a ARC en el camino, puede usar diferentes llamadas de tiempo de ejecución, o las llamadas pueden utilizar datos locales de subprocesos de manera diferente si las llamadas inyectadas se actualizan.
Los detalles sobre la especificación de ARC en lo que respecta al tiempo de ejecución se pueden encontrar aquí: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime
Un problema similar fue visto aquí:
No dices de qué parte myCGLayer
nosotros, pero tomaré una foto y diré que no se deriva de CGLayer, porque CGLayer no tiene una propiedad backgroundColor
. Así que supongo (nuevamente) que el parámetro pasado debe ser del tipo UIColor y no de CGColor. CGColor se deriva de la clase CFType. UIColor se deriva de NSObject. No deberían ser intercambiables. Si mis suposiciones son correctas, me sorprende que funcione en el simulador.
No me abofeteen demasiado si mis suposiciones son incorrectas.