Existe uma razão pela qual eu não pode inicializar um CALayer fora de uma classe UIView?

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

  •  03-07-2019
  •  | 
  •  

Pergunta

Eu tenho tentado para nos CALayers como "sprites" em um aplicativo para iPhone que estou trabalhando. Pelo que tenho lido, que parece ser a coisa certa a fazer aqui.

Quando eu configuração da camada dentro de uma classe UIView eu sou capaz de conseguir a camada aparecer na tela: 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];

No entanto, quando tento inicializar o CALayer fora do UIView, meu aplicativo trava:

- (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]];

É evidente que eu estou fazendo algo errado aqui, mas eu simplesmente não sei o que seria. Eu li o Core Animation Guia de Programação e também o iPhone Application Programming Guide, mas eles realmente não parecem falar sobre como inicializar um CALayer diferente de passagem.

Eu só preciso de um pequeno empurrão na direção correta. Fui ficando um bom muito compreensão sobre tudo o que eu aprendi quando se trata de programação do iPhone. Eu só estou tendo alguns problemas com gráficos, Layers e Animation.

Agradecemos antecipadamente!

Foi útil?

Solução

Você não possuem a camada que você começa a partir do método layer, então você tem que tomar posse. Algum tempo depois de suas declarações de método, a camada está sendo desalocada e que está causando a sua queda. Para curar esta:

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

Além disso, não se esqueça de liberar a camada uma vez que ele próprio agora:

// in your dealloc method
[layer release];

Você deve rever o href="http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html" rel="nofollow noreferrer"> Gestão para mais detalhes sobre quando você possui objetos e quais são as suas responsabilidades em matéria de gestão de memória.

Outras dicas

Jason, muito obrigado por responder! No entanto a sua resposta não parece ter qualquer efeito sobre o resultado do meu problema.

Na verdade, a resposta "é" algo relacionado ao gerenciamento de memória. Não a camada, mas o nome que eu tenho do NSArray depois de chamar componentsSeparatedByString :. Se eu não liberar o NSArray, o código funciona bem. Então eu preciso fazer uma cópia do NSString dentro da matriz em vez de usar o objeto na matriz.

Eu tenho que dizer que eu não li o gerenciamento de memória Guia de Programação de Cacau como você sugere. No entanto, eu li vários outros livros que falou sobre o padrão utilizado em Cocoa para objetos criados e seus reter contagem. Eu tenho uma compreensão justa, mas, aparentemente, não tão bom quanto necessário ainda.

Eu realmente tinha uma suspeita de que eu deveria copiar a cadeia para fora da matriz, mas quando ele trabalhou no UIView, eu só assumiu que era correto. O problema era, eu não estava mantendo como estou dentro do meu objeto GamePiece.

Obrigado por, pelo menos, ficando-me a olhar na direção certa! Eu estava realmente no juízo final com este código.

Para fazer o que você queria, aqui está como você pode mudar seu código. Em loadImage: usar essa linha para adicionar o UIImage você carregado na camada earth:

self.conteudo = image.CGImage;

CALayers tem uma propriedade contents que você pode ajustar a um CGImage em vez de passar pelo problema do uso de Core Graphics chama para desenhar a imagem no contexto da camada.

Em seguida, na subclasse UIView pai, você pode adicionar o earth à hierarquia vista como esta:

[self.layer addSublayer: Terra];

Note que earth é em si um CALayer com uma imagem como o seu conteúdo assim que eu adicioná-lo diretamente como uma subcamada. A outra coisa que eu sempre esqueço de fazer é definir propriedade frame da camada. Caso contrário, sua largura e altura será zero e por isso não vai mostrar.

Em seu código você criou uma camada, mas nunca adicionado a sua camada à hierarquia vista. Há uma árvore, se vistas (classe UIView) e seus subviews. A raiz da árvore é [UIWindow mainwindow] (aviso de que UIWindow é uma subclasse de UIView. Cada UIView tem uma propriedade layer do tipo CALayer que realmente detém o seu conteúdo visível. UIView é apenas um invólucro em torno CALayer para adicionar coisas como lidar com toque capacidade .

A idéia importante que está faltando aqui é que, para qualquer coisa para estar visível na tela tem que ser parte desta árvore de pontos de vista com um UIWindow como sua raiz e todos os pontos de vista devem ser visíveis (ou seja, ter sua propriedade hidden definido como NO) entre a janela de nível superior e a camada em questão. Só então uma camada de ser visível na tela. Então, em algum lugar em seu código que você precisa adicionar a sua camada como uma subcamada de algo já visível chamando addSublayer:.

No seu caso, estou assumindo earth é uma instância de uma CALayer e que você tem feito dentro do método loadImage: é criar uma nova CALayer (com uma chamada para [CALayer layer]) dentro da camada earth mas então você nunca acrescentou que nova camada a qualquer coisa para que ele nunca se tornou visível. O que você fez em vez disso é tentar adicionar a camada earth, que ainda não tem qualquer conteúdo, para que eu assumo é a camada de um UIView

[[auto camada] addSublayer: camada de terra []];

Um problema com esta linha é que você parece estar pensando layer é uma propriedade do earth. Na verdade layer é um método de classe de CALayer que é um método de fábrica para criar novas instâncias de CALayer. Esta é confuso porque [self layer] realmente está acessando a propriedade de camada de uma instância UIView. (Estou assumindo self refere-se a um exemplo de uma subclasse UIView.)

scroll top