关于iphone:在iOS上,如果CALayer的一个子类与一个空的显示方法一起使用,那么app似乎进入了无限循环?

On iOS, if a subclass of CALayer is used with an empty display method, then app seems to go into infinite loop?

如果创建了一个单视图应用程序,其 FooViewUIView 的子类,然后执行一个

1
NSLog(@"hello");

in drawRect,然后打印出来。

如果我创建一个名为 CoolLayerCALayer 子类,并将这个方法添加到 FooView.m:

1
2
3
+(Class) layerClass {
    return [CoolLayer class];
}

FooView.mdrawRect的末尾,做一个

1
NSLog(@"layer's class is %@", self.layer.class);

然后 CoolLayer 被打印。所以现在视图的底层是 CoolLayer.

但是当将以下内容添加到 CoolLayer.m 时:

1
2
3
-(void) display {

}

这是自动调用以重绘图层的方法(类似于 drawRect),然后没有打印任何 NSLog。可能是应用程序进入了无限循环。 (即使我的 touchesBegan 打印出 NSLog 消息也没有打印)。如果在 display 处设置断点,它会停在那里一次,但是当我继续程序时,它永远不会再到达 display 处。这有什么问题,如何解决?


图层的显示方法不会被再次调用,除非图层是脏的,即设置为需要重新显示。这通常是一件好事,这就是为什么您不会看到该方法被多次调用的原因。

另外,display的正常实现会调用drawInContext:方法。由于您在子类中覆盖了它,因此永远不会调用视图的 drawRect: 方法。您需要复制 CALayer 的标准行为,或者在您自己的实现中调用超类的 display 方法。


这听起来不像是无限循环。如果您处于无限循环中,您的应用程序将冻结,几秒钟后,跳板应用程序会因无响应而终止它。

在您的图层上调用 setNeedsDisplay 或 setNeedsDisplayInRect 以使其"脏"并要求再次绘制。请注意,您不必再调用 setNeedsDisplay,因为重新渲染图层并将其内容推送到屏幕上需要大量工作。仅在某些内容发生更改时显示


您在这里没有看到无限循环。如果你是,正如 Duncan 指出的那样,你最终会因为看门狗定时器或无限递归而崩溃,这在你在调试器中看到的堆栈跟踪中会立即显而易见。

如果您将 NSLog 放入 UIView 的 -drawRect: 方法中,然后使用您自己的自定义 CALayer 覆盖其默认图层类,该 CALayer 会进行自己的绘图,您的 UIView 的 -drawRect: 将不再被调用。绘图现在将由您的自定义支持层处理。

如核心动画编程指南的"通过子类化提供 CALayer 内容"小节中所述,如果您想以某种方式自定义图层的 contents CGImageRef,您通常会在 CALayer 中覆盖 -display。通常,如果您想在 CALayer 中渲染自定义 Quartz 绘图,您将覆盖 -drawInContext:。使您被覆盖的 -display 方法完全空白,并且不向 contents 属性写入任何内容,这不是标准行为,所以我对您看到这样做的奇怪结果并不感到惊讶。

根据您最近提出的一系列问题,我强烈建议您停下来花一些时间阅读 Core Animation Programming Guide 并查看一些涉及 CALayers 的示例代码,然后再继续。