¿Hay alguna razón por la que no pueda inicializar un CALayer fuera de una clase UIView?

StackOverflow https://stackoverflow.com/questions/805265

  •  03-07-2019
  •  | 
  •  

Pregunta

He estado intentando con nosotros CALayers como " sprites " En una aplicación para iPhone en la que estoy trabajando. Por lo que he estado leyendo, eso parece ser lo correcto a hacer aquí.

Cuando configuro la capa dentro de una clase UIView, puedo hacer que la capa aparezca en la pantalla:     NSLog (@ " GameView initWithCoder ");

NSString* imagePath = [[NSBundle mainBundle] pathForResource:@"earth" ofType:@"png"];
earthImage = [[UIImage alloc] initWithContentsOfFile:imagePath];

earthLayer = [CALayer layer];
[earthLayer setContents:(id)[earthImage CGImage]];
[earthLayer setBounds:CGRectMake(0, 0, 32, 32)];
[earthLayer setPosition:CGPointMake(50, 50)];
[earthLayer setName:@"earth"];

[[self layer] addSublayer:earthLayer];

Sin embargo, cuando intento inicializar CALayer fuera de UIView, mi aplicación se bloquea:

- (void)loadImage:(NSString*)fileName
{
  NSLog(@"GamePiece loadImage");
  NSArray* fileNameParts = [fileName componentsSeparatedByString:@"."];
  imageName = [[fileNameParts objectAtIndex:0] retain];
  NSString* ext = [fileNameParts objectAtIndex:1];

  NSString* imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:ext];
  image = [[UIImage alloc] initWithContentsOfFile:imagePath];

  layer = [CALayer layer];
  [layer setContents:(id)[image CGImage]];

  [layer setBounds:CGRectMake(0.0f, 0.0f, 32.0f, 32.0f)];
  [layer setPosition:CGPointMake(50.0f, 50.0f)];
  [layer setName:imageName];

  [fileNameParts release], fileNameParts = nil;
  [ext release], ext = nil;
}

NSLog(@"GameView initWithCoder");
earth = [[GamePiece alloc] init];
[earth loadImage:@"earth.png"];

[[self layer] addSublayer:[earth layer]];

Claramente estoy haciendo algo mal aquí, pero simplemente no sé qué sería eso. He leído la Guía de programación de Core Animation y también la Guía de programación de aplicaciones de iPhone, pero realmente no parecen hablar de cómo inicializar un CALayer que no sea de pasada.

Sólo necesito un suave empujón en la dirección correcta. He comprendido bastante bien todo lo demás que he aprendido en lo que respecta a la programación del iPhone. Solo tengo algunos problemas con Gráficos, Capas y Animación.

Gracias de antemano!

¿Fue útil?

Solución

No es propietario de la capa que obtiene del método layer , por lo que tiene que tomar posesión. Algún tiempo después de que regrese su método, la capa se está desasignando y eso está causando su caída. Para curar esto:

layer = [[CALayer layer] retain]; // now we explicitly take ownership of this layer

Además, no olvides liberar la capa, ya que ahora la tienes:

// in your dealloc method
[layer release];

Debe revisar la Guía de programación de administración de memoria para Cocoa para obtener más detalles sobre cuándo posee los objetos y cuáles son sus responsabilidades con respecto a la administración de la memoria.

Otros consejos

¡Jason, muchas gracias por responder! Sin embargo, su respuesta no parece tener ningún efecto en el resultado de mi problema.

En realidad, la respuesta " es " Algo relacionado con la gestión de la memoria. No es la capa, pero el nombre que recibí de NSArray después de llamar a componentsSeparatedByString :. Si no libero el NSArray, el código funciona bien. Así que necesito hacer una copia de la NSString dentro de la matriz en lugar de usar el objeto en la matriz.

Tengo que decir que no he leído la Guía de programación de gestión de memoria para Cocoa como sugieres. Sin embargo, he leído varios otros libros que hablaron sobre el estándar utilizado en Cocoa para los objetos creados y sus recuentos. Tengo una comprensión justa, pero al parecer, todavía no es tan buena como se necesita.

Realmente tuve la sospecha de que debería copiar la cadena de la matriz, pero cuando funcionó en la vista UIV, asumí que era correcta. El problema era que no lo guardaba como si estuviera dentro de mi objeto GamePiece.

¡Gracias por al menos lograr que mire en la dirección correcta! Estaba realmente en ingenioso fin con este código.

Para hacer lo que querías, aquí es cómo puedes cambiar tu código. En loadImage: use esta línea para agregar el UIImage que cargó en la capa earth :

  

self.contents = image.CGImage;

CALayers tiene una propiedad de contents que puede configurar en CGImage en lugar de pasar por la molestia de usar las llamadas Core Graphics para dibujar el imagen en el contexto de la capa.

Luego, en la subclase UIView principal, puede agregar earth a la jerarquía de vistas de esta manera:

  

[self.layer addSublayer: earth];

Tenga en cuenta que earth es en sí mismo un CALayer con una imagen como contenido, así que lo agrego directamente como subcapa. La otra cosa que siempre olvido es establecer la propiedad frame de la capa. De lo contrario, su anchura y altura serán cero y, por lo tanto, no se mostrarán.

En su código, creó una capa, pero nunca la agregó a la jerarquía de vistas. Hay un árbol si las vistas (clase UIView) y sus subvistas. La raíz del árbol es [UIWindow mainwindow] (observe que UIWindow es una subclase de UIView . Cada UIView tiene una propiedad layer de tipo < code> CALayer que en realidad contiene su contenido visible. UIView es solo un envoltorio alrededor de CALayer para agregar elementos como la capacidad de manejo táctil.

La idea importante que se está perdiendo aquí es que para que cualquier cosa sea visible en la pantalla tiene que ser parte de este árbol de vistas con una ventana UI en su raíz y todas las vistas deben estar visibles (es decir, tienen su la propiedad oculta establecida en NO ) entre la ventana de nivel superior y la capa en cuestión. Solo así se podrá ver una capa en la pantalla. Entonces, en algún lugar de tu código necesitas agregar tu capa como subcapa de algo que ya está visible llamando a addSublayer: .

En su caso, asumo que earth es una instancia de CALayer y lo que hizo dentro del método loadImage: es cree un nuevo CALayer (con una llamada a [CALayer layer] ) dentro de la capa earth , pero luego nunca agregó esa nueva capa a nada. nunca se hizo visible. Lo que hiciste en su lugar es intentar agregar la capa earth , que aún no tiene contenido, a lo que supongo que es la capa de UIView

  

[[self layer] addSublayer: [earth layer]];

Un problema con esta línea es que parece que estás pensando que layer es una propiedad de earth . En realidad, layer es un método de clase de CALayer que es un método de fábrica para crear nuevas instancias de CALayer . Esto es confuso porque [self layer] en realidad está accediendo a la propiedad de capa de una instancia de UIView . (Supongo que self se refiere a una instancia de una subclase de UIView )

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top