Reputation: 2113
This issue really has me stumped...
I have an iPad project that I use UIPanGestureRecognizer and I am using the following method call within my 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;
}
Once I "find" an AIEnemyUnit layer, I continue with the drag and everything works fine. Except about around the 6th to 10th "drag" I get a crash with the debugger deep within only the 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'
Upvotes: 1
Views: 1815
Reputation: 693
I think there's a bit of 'misinformation' in the hitTest documentation actually. I ran into a similar problem myself putting 4 instances of a subclassed view onto the window, each with four sublayers in it. Each of the 4 view subclasses had a touchesBegan:withEvent method and a touchesEnded:withEvent method defined. I found that if my touch landed or ended in the top-left most view, my hitTest returned a valid sublayer. However, hitTests in any of the other three views returned nil for the sublayer. Like you, I was totally stumped until I decided to replace the touch point in the view's co-ordinate system with one for the window's co-ordinate system and then it all worked. I reproduce the documentation for the hitTest method:
hitTest: Returns the farthest descendant of the receiver in the layer hierarchy (including itself) that contains a specified point.
- (CALayer *)hitTest:(CGPoint)thePoint
Parameters thePoint A point in the coordinate system of the receiver's superlayer. Return Value The layer that contains thePoint, or nil if the point lies outside the receiver’s bounds rectangle.
Availability Available in Mac OS X v10.5 and later. Declared In CALayer.h
I would argue, based on my observations, that the explanation of 'thePoint' is wrong. I think it should read 'A point in the coordinate system of the window containing the receiver.' I think the only reason the top-left view gave valid hitTests was because the co-ordinates of the touch - in that location - are the same as the co-ordinates of the touch in the window. Don't know if this helps you but it's helped me get my logic working. V.V.
Upvotes: 0
Reputation: 29518
From the symptoms it looks like you have an over-release of a CALayer.
Two areas you should check:
1) Are you 'saving' this CALayer
in a variable without retaining it? If you're hitting any autorelease pools (including the one supplied on the main thread) then these layers could be getting released unintentionally. As noted in the comments, since these aren't autoreleased, this can happen without hitting a pool. It can happen anytime the CALayer is released while you're holding a reference however.
2) You're explicitly calling release on this layer later on. Since you are given this layer as is (both hitTest:
and superlayer
return objects without an extra retain count) you do not have ownership, and thus should not release it.
Another useful tool for debugging is using NSZombies, and some other techniquies linked there. NSZombies basically allows your application to crash the moment you access a released object, which hopefully will give you a more meaningful stack trace.
Upvotes: 1