【问题标题】:Is there a reason I can't initialize a CALayer outside a UIView class?我不能在 UIView 类之外初始化 CALayer 有什么原因吗?
【发布时间】:2010-10-22 18:14:19
【问题描述】:

我一直在尝试将我们的 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 编程方面,我对所学的所有其他知识都有了很好的理解。我只是在图形、图层和动画方面遇到了一些问题。

提前致谢!

【问题讨论】:

    标签: iphone uiview calayer


    【解决方案1】:

    您不拥有从layer 方法获得的层,因此您必须拥有所有权。在您的方法返回后的某个时间,该层正在被释放,这会导致您的崩溃。要解决这个问题:

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

    另外,不要忘记释放该层,因为您现在拥有它:

    // in your dealloc method
    [layer release];
    

    您应该查看Memory Management Programming Guide for Cocoa,了解有关您何时拥有对象以及您在内存管理方面的职责的更多详细信息。

    【讨论】:

      【解决方案2】:

      杰森,非常感谢您的回复!但是,您的回答似乎对我的问题的结果没有任何影响。

      实际上,答案“是”与内存管理有关的东西。不是Layer,而是我在调用componentsSeparatedByString:后从NSArray中得到的名字。如果我不释放 NSArray,则代码可以正常工作。所以我需要在数组中复制 NSString 而不是使用数组中的对象。

      我不得不说我没有按照你的建议阅读 Cocoa 的内存管理编程指南。但是,我读过其他几本书,这些书谈到了 Cocoa 中用于创建对象及其保留计数的标准。我有一个公平的理解,但显然,还没有需要的那么好。

      我真的怀疑我应该从数组中复制字符串,但是当它在 UIView 中工作时,我只是假设它是正确的。问题是,我没有像在我的 GamePiece 对象中那样保持它。

      感谢您至少让我找到了正确的方向!我真的对这段代码束手无策。

      【讨论】:

      • 其实层还是有问题的,即使到目前为止你已经很幸运了。如果它是 ivar,则必须保留它。至于文件名,我错过了。您实际上不必保留或复制它。只是不要发布它 :) 基本上,您只在函数期间使用的东西不需要主动管理,除非您创建它们(alloc/copy/new)。您想要保留的东西需要积极管理(因此,如果您没有分配/复制/新建,则必须保留)。
      【解决方案3】:

      要做你想做的事,这里是你可以改变你的代码的方法。在loadImage: 中使用这一行将您加载的UIImage 添加到earth 层中:

      self.contents = image.CGImage;

      CALayers 有一个contents 属性,您可以将其设置为CGImage,而不必费心使用Core Graphics 调用将图像绘制到图层的上下文中。

      然后在父类UIView 子类中,您可以像这样将earth 添加到视图层次结构中:

      [self.layer addSublayer:earth];

      注意earth 本身就是一个CALayer,其内容是图像,所以我直接将其添加为子图层。我总是忘记做的另一件事是设置图层的frame 属性。否则它的宽度和高度将为零,因此不会显示。

      在您的代码中,您创建了一个层,但从未将您的层添加到视图层次结构中。如果视图(UIView 类)及其子视图存在树。树的根是 [UIWindow mainwindow](注意 UIWindow 是UIView 的子类。每个UIView 都有一个layer 类型的CALayer 属性,它实际上保存了它的可见内容。UIView 只是一个包装 CALayer 以添加触摸处理能力等内容。

      您在这里缺少的重要想法是,要在屏幕上显示任何内容,它必须是该视图树的一部分,并以 UIWindow 作为其根,并且所有视图都必须可见(即具有它们的 @987654338 @property 设置为 NO) 在顶层窗口和相关层之间。只有这样,一个图层才会在屏幕上可见。因此,您需要在代码中的某处通过调用 addSublayer: 将您的层添加为已经可见的事物的子层。

      在您的情况下,我假设 earthCALayer 的一个实例,而您在 loadImage: 方法中所做的是在其中创建一个新的 CALayer(调用 [CALayer layer]earth 层,但是您从未将该新层添加到任何东西中,因此它永远不会变得可见。您所做的是尝试将仍然没有任何内容的earth 层添加到我认为是UIView 的层

      [[自身层] addSublayer:[地层]];

      这一行的一个问题是您似乎认为layerearth 的属性。实际上layerCALayer 的一个类方法,它是创建CALayer 新实例的工厂方法。这很令人困惑,因为 [self layer] 实际上是在访问 UIView 实例的 layer 属性。 (我假设self 指的是UIView 子类的一个实例。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-05-19
        • 2021-08-03
        • 1970-01-01
        • 1970-01-01
        • 2020-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多