Y a-t-il une raison pour laquelle je ne peux pas initialiser un CALayer en dehors d'une classe UIView?

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

  •  03-07-2019
  •  | 
  •  

Question

J’ai essayé de nous faire passer en tant que "sprites" dans une application iPhone sur laquelle je travaille. D'après ce que j'ai lu, cela semble être la bonne chose à faire ici.

Lorsque je configure la couche dans une classe UIView, je peux la faire apparaître à l'écran:     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];

Cependant, lorsque je tente d'initialiser CALayer en dehors de UIView, mon application se bloque:

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

Clairement, je fais quelque chose de mal, mais je ne sais pas ce que ce serait. J'ai lu le Guide de programmation Core Animation et le Guide de programmation d'applications iPhone, mais ils ne semblent vraiment pas parler de la procédure d'initialisation d'un CALayer autrement qu'en passant.

J'ai juste besoin d'un léger coup de pouce dans la bonne direction. Je comprends assez bien tout ce que j'ai appris en matière de programmation de l'iPhone. J'ai juste quelques problèmes avec les graphiques, les calques et les animations.

Merci d'avance!

Était-ce utile?

La solution

Vous ne possédez pas le calque que vous obtenez de la méthode layer , vous devez donc en prendre possession. Quelque temps après le retour de votre méthode, la couche est désallouée et cela provoque votre plantage. Pour remédier à cela:

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

N'oubliez pas non plus de libérer le calque, car vous le possédez maintenant:

// in your dealloc method
[layer release];

Vous devriez consulter le Guide de programmation de la gestion de la mémoire pour Cocoa pour plus de détails sur le moment où vous possédez des objets et sur vos responsabilités en matière de gestion de la mémoire.

Autres conseils

Jason, merci beaucoup d'avoir répondu! Cependant, votre réponse ne semble pas avoir d’effet sur l’issue de mon problème.

En fait, la réponse " est " quelque chose lié à la gestion de la mémoire. Pas le calque, mais le nom que j'ai reçu de NSArray après avoir appelé componentsSeparatedByString :. Si je ne libère pas le NSArray, le code fonctionne bien. Je dois donc faire une copie de NSString à l'intérieur du tableau au lieu d'utiliser l'objet du tableau.

Je dois dire que je n'ai pas lu le Guide de programmation de la gestion de la mémoire pour Cocoa, comme vous le suggérez. Cependant, j'ai lu plusieurs autres livres qui parlaient de la norme utilisée dans Cocoa pour les objets créés et de leur valeur de conservation. Je comprends assez bien, mais apparemment, je ne suis pas aussi bon que nécessaire.

Je soupçonnais vraiment que je devais copier la chaîne hors du tableau, mais quand cela fonctionnait dans UIView, je pensais simplement que c'était correct. Le problème était que je ne le gardais pas comme si j'étais à l'intérieur de mon objet GamePiece.

Merci de m'avoir au moins amené à regarder dans la bonne direction! J'étais vraiment au bout du rouleau avec ce code.

Pour faire ce que vous voulez, voici comment modifier votre code. Dans loadImage: , utilisez cette ligne pour ajouter le UIImage que vous avez chargé dans la couche earth :

  

self.contents = image.CGImage;

CALayers ont une propriété contents que vous pouvez définir sur CGImage plutôt que de passer par la difficulté d'utiliser des appels Core Graphics pour dessiner le image dans le contexte de la couche.

Ensuite, dans la sous-classe parent UIView , vous pouvez ajouter le earth à la hiérarchie des vues, comme suit:

  

[self.layer addSublayer: earth];

Notez que earth est lui-même un CALayer avec une image pour contenu, je l’ajoute donc directement en tant que sous-couche. L'autre chose que j'oublie toujours de faire est de définir la propriété frame de la couche. Sinon, sa largeur et sa hauteur seront égales à zéro et ne seront donc pas affichées.

Dans votre code, vous avez créé un calque mais vous ne l'avez jamais ajouté à la hiérarchie des vues. Il y a une arborescence si les vues (classe UIView) et leurs sous-vues. La racine de l'arbre est [UIWindow mainwindow] (notez que UIWindow est une sous-classe de UIView . Chaque UIView a une propriété layer de type < code> CALayer qui contient en réalité son contenu visible. UIView est juste un wrapper autour de CALayer pour ajouter des éléments tels que la capacité de manipulation tactile.

L’idée importante qui vous manque ici est que pour que toute chose soit visible à l’écran, elle doit faire partie de cet arbre de vues avec UIWindow comme racine et toutes les vues doivent être visibles (c’est-à-dire que leur hidden définie sur NO ) entre la fenêtre de niveau supérieur et le calque en question. Alors seulement, un calque sera visible à l'écran. Donc, quelque part dans votre code, vous devez ajouter votre couche en tant que sous-couche de quelque chose déjà visible en appelant addSublayer: .

Dans votre cas, je suppose que earth est une instance de CALayer et ce que vous avez fait dans la méthode loadImage: est créer un nouveau CALayer (avec un appel à [couche calque] ) au sein de la couche earth mais vous n'aurez jamais ajouté cette couche à quoi que ce soit il n'est jamais devenu visible. Au lieu de cela, vous avez tenté d’ajouter le calque earth , qui n’a toujours pas de contenu, à ce que je suppose être un calque UIView

.
  

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

Un problème avec cette ligne est que vous semblez penser que la couche est une propriété de earth . En réalité, layer est une méthode de classe de CALayer , qui est une méthode fabrique pour créer de nouvelles instances de CALayer . Cela est source de confusion car [couche auto] est en train d'accéder à la propriété layer d'une instance UIView . (Je suppose que self fait référence à une instance d'une sous-classe UIView .)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top