views:

509

answers:

2

I have been trying to us CALayers as "sprites" in an iPhone application I'm working on. From what I have been reading, that seems like the correct thing to do here.

When I setup the layer inside a UIView class I am able to get the layer to show up on the screen: 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];

However, when I attempt to initialize the CALayer outside the UIView, my application crashes:

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

Clearly I'm doing something wrong here, but I just don't know what that would be. I have read the Core Animation Programming Guide and also the iPhone Application Programming Guide, but they really don't seem to talk about how to initialize a CALayer other than in passing.

I just need a gentle nudge in the correct direction. I have been getting a pretty good understanding about everything else I have learned when it comes to programming the iPhone. I'm just having some issues with Graphics, Layers and Animation.

Thanks in advance!

+1  A: 

You don't own the layer that you get from the layer method, so you have to take ownership. Sometime after your method returns, the layer is being deallocated and that is causing your crash. To cure this:

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

Also, don't forget to release the layer since you own it now:

// in your dealloc method
[layer release];

You should review the Memory Management Programming Guide for Cocoa for more details on when you own objects and what your responsibilities are regarding memory management.

Jason Coco
A: 

Jason, thank you so much for responding! However your answer doesn't seem to have any effect on the outcome of my problem.

Actually, the answer "is" something related to memory management. Not the Layer, but the name I got from the NSArray after calling componentsSeparatedByString:. If I don't release the NSArray, the code works fine. So I need to make a copy of the NSString inside the array instead of using the object in the array.

I have to say that I haven't read the Memory Management Programming Guide for Cocoa as you suggest. However, I have read several other book that talked about the standard used in Cocoa for objects created and their retain counts. I have a fair understanding, but apparently, not as good as needed yet.

I really had a suspicion that I should copy the string out of the array, but when it worked in the UIView, I just assumed that it was correct. Problem was, I wasn't keeping it like I am inside my GamePiece object.

Thank you for at least getting me to look in the right direction! I was really at wits end with this code.

VesperDEM
Actually, the layer is still a problem, even if you've been lucky so far. You have to retain it if it's an ivar. As for the file name, I missed that. You don't actually have to retain or copy that. Just don't release it :) Basically, things that you only use during the duration of your function don't need to be actively managed unless you created them (alloc/copy/new). Things that you want to stick around need to be actively managed (so if you didn't alloc/copy/new you must retain).
Jason Coco