[英]Is there a reason I can't initialize a CALayer outside a UIView class?
我一直在尝试将CALayers作为我正在研究的iPhone应用程序中的“精灵”。 从我一直在阅读的内容来看,这似乎是正确的事情。
当我在UIView类中设置图层时,我能够让图层显示在屏幕上: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];
但是,当我尝试在UIView外部初始化CALayer时,我的应用程序崩溃了:
- (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]];
显然我在这里做错了,但我不知道那是什么。 我已经阅读了“核心动画编程指南”和“iPhone应用程序编程指南”,但他们似乎并没有谈论如何初始化CALayer而不是传递。
我只需要在正确的方向上轻轻推动。 在编程iPhone时,我对其他所有学到的东西都有了很好的理解。 我只是在图形,图层和动画方面遇到了一些问题。
提前致谢!
您不拥有从layer
方法获得的layer
,因此您必须拥有所有权。 在您的方法返回之后的某个时间,该层正在被释放,这导致您的崩溃。 解决这个问题:
layer = [[CALayer layer] retain]; // now we explicitly take ownership of this layer
此外,不要忘记释放图层,因为您现在拥有它:
// in your dealloc method
[layer release];
您应该查看Cocoa内存管理编程指南,了解有关何时拥有对象以及您在内存管理方面的职责的更多详细信息。
要做你想做的事,你可以在这里改变你的代码。 在loadImage:
使用此行添加加载到earth
图层的UIImage
:
self.contents = image.CGImage;
CALayers
有一个contents
,你可以设置一个属性CGImage
,而不是通过使用核芯显卡的麻烦会调用图像绘制到该层的上下文。
然后在父UIView
子类中,您可以将earth
添加到视图层次结构中,如下所示:
[self.layer addSublayer:earth];
请注意, earth
本身就是一个CALayer
其中包含图像作为其内容,因此我将其直接添加为子图层。 我总是忘记做的另一件事是设置图层的frame
属性。 否则它的宽度和高度将为零,因此不会显示。
在您的代码中,您创建了一个图层,但从未将图层添加到视图层次结构中。 如果视图(类UIView)及其子视图有一棵树。 树的根是[UIWindow mainwindow](注意UIWindow是UIView
的子类。每个UIView
都有一个类型为CALayer
的layer
属性,它实际上保存着它的可见内容UIView
只是CALayer
一个包装器,用于添加触摸处理能力之类的东西。
您在这里缺少的重要想法是,对于屏幕上可见的任何内容,它必须是UIWindow作为其根的所有视图的一部分,并且所有视图必须是可见的(即将其hidden
属性设置为NO
)在顶层窗口和有问题的层之间。 只有这样才能在屏幕上看到一个图层。 因此,在代码中的某处,您需要通过调用addSublayer:
将您的图层添加为已经可见的内容的子图层addSublayer:
。
在你的情况下,我假设earth
是CALayer
一个实例,你在loadImage:
method中所做的是在earth
层内创建一个新的CALayer
(调用[CALayer layer]
)但是你从未添加过新层到任何东西,所以它永远不会变得可见。 你所做的是尝试添加earth
层,它仍然没有任何内容,我假设是UIView
的层
[[self layer] addSublayer:[earth layer]];
这一行的一个问题是你似乎认为layer
是earth
的属性。 实际上, layer
是CALayer
的类方法,它是一种创建CALayer
新实例的工厂方法。 这很令人困惑,因为[self layer]
实际上正在访问UIView
实例的layer属性。 (我假设self
指的是UIView
子类的一个实例。)
杰森,非常感谢你的回应! 但是你的答案似乎对我的问题的结果没有任何影响。
实际上,答案“是”与内存管理相关的东西。 不是Layer,而是在调用componentsSeparatedByString后从NSArray获得的名称。 如果我不释放NSArray,代码工作正常。 所以我需要在数组中复制NSString而不是使用数组中的对象。
我不得不说,我没有按照你的建议阅读Cocoa的内存管理编程指南。 但是,我已经阅读了其他几本书,其中讨论了Cocoa中用于创建对象的标准及其保留计数。 我有一个公平的理解,但显然,还没有那么好。
我真的怀疑我应该将字符串复制出数组,但是当它在UIView中工作时,我只是认为它是正确的。 问题是,我没有像我在GamePiece对象中那样保持它。
感谢您至少让我朝着正确的方向前进! 我真的很擅长这段代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.