在CALayer -hitTest中崩溃:

时间:2010-09-28 06:19:39

标签: iphone cocoa-touch ipad calayer uigesturerecognizer

这个问题真让我难过......

我有一个iPad项目,我使用UIPanGestureRecognizer,我在handlePanGesture中使用以下方法调用:

- (AIEnemyUnit *) hitTestForEnemyUnit:(CGPoint)where {
    CALayer * layer = [self hitTest:where];

    while (layer) {
        if ([layer isKindOfClass:[AIEnemyUnit class]]) {
            return (AIEnemyUnit *)layer;
        } else {
            layer = layer.superlayer;
        }
    }

    return nil;
}

一旦我“找到”AIEnemyUnit图层,我继续拖动,一切正常。除了大约在第6到第10次“拖动”之外,我只在CALayer -hitTest内部调试器崩溃:

modifying layer that is being finalized - 0x124530
*** -[NSCFSet hitTest:]: unrecognized selector sent to instance 0x124530
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', 
reason: 
'*** -[NSCFSet hitTest:]: unrecognized selector sent to instance 0x124530'

2 个答案:

答案 0 :(得分:1)

从症状看,您的CALayer过度释放。

您应该检查的两个方面:

1)您是否在不保留变量的情况下将此CALayer保存在变量中?如果您正在访问任何自动释放池(包括主线程上提供的那个),那么这些层可能会无意中被释放。正如评论中所指出的,由于这些不是自动释放的,因此可以在不命中池的情况下发生。无论何时释放CALayer,都可能发生这种情况。

2)您稍后将在此图层上明确调用release。由于您按原样获得此图层(hitTest:superlayer返回对象而没有额外的保留计数)您没有所有权,因此不应该释放它。

调试的另一个有用工具是使用NSZombies,以及其他一些技术。 NSZombies基本上允许您的应用程序在您访问已发布对象时崩溃,这有望为您提供更有意义的堆栈跟踪。

答案 1 :(得分:0)

我认为hitTest文档实际上存在一些“错误信息”。我遇到了类似的问题,我自己将4个子类视图实例放到窗口上,每个子窗口都有4个子层。 4个视图子类中的每一个都有一个touchesBegan:withEvent方法和一个touchesEnded:withEvent方法定义。我发现如果我的触摸在最左上角的视图中着陆或结束,我的hitTest返回了一个有效的子图层。但是,其他三个视图中的任何一个中的hitTests都返回nil作为子图层。和你一样,直到我决定用视窗坐标系统中的触点替换窗口的坐标系统中的接触点然后一切都工作之前,我一直都很难过。我重现了hitTest方法的文档:

则hitTest: 返回包含指定点的图层层次结构(包括其自身)中接收器的最远后代。

- (CALayer *)hitTest:(CGPoint)thePoint

参数 thePoint 接收器超层的坐标系中的一个点。 回报价值 包含Point的图层,如果该点位于接收器的边界矩形之外,则为nil。

状况 适用于Mac OS X v10.5及更高版本。 宣告进入 CALayer.h

根据我的观察,我认为'thePoint'的解释是错误的。我认为它应该是'包含接收器的窗口坐标系中的一个点'。我认为左上角视图给出有效hitTests的唯一原因是因为触摸的坐标 - 在该位置 - 与窗口中触摸的坐标相同。不知道这是否对你有所帮助,但这有助于我的逻辑运作。 V.V。