在整个网站上使用各种关于如何做目标c的例子,我想创建一个需要识别长按和单击的应用程序。我的应用程序的代码具有以下功能(为简洁起见省略了部分,实际代码编译正常,下面的代码是手动输入的,所以请不要指出语法错误):
从CCScene派生的基类(让我们称之为LongPressHandlingScene) 一个。此类在“init”期间设置UILongPressGestureRecognizer并将其“onExit”删除 湾这个类有一个方法,作为“长按”手势的事件处理程序(它自己使用时工作正常) 湾该类的其余部分与任何其他CCScene类相同。
//LongPressHandlingScene.h
@interface LongPressHandlingScene : CCScene {
......
}
..........
@end
//LongPressHandlingScene.m
@implementation LongPressHandlingScene{
.............
}
-(id)init{
{
if(!(self = [super init]))
return nil;
.........
UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longTouchAction:)];
return self;
}
..............
-(void)longTouchAction:(UILongPressGestureRecognizer *)longTouch{
..........
}
-(void)onExit{
NSArray *grs = [[[CCDirector sharedDirector] view] gestureRecognizers];
for(UIGestureRecognizers *gesture in grs){
if([gesture isKindOfClass:[UILongPressGestureRecognizer class]]){
[[[CCDirector sharedDirector] view] removeGestureRecognizer:gesture];
}
@end
从CCSprite派生的基类(我们称之为DragHandlingSprite) 一个。这个类重写了touchBegan,touchMoved和touchEnded。 (在CCScene或CCScene派生类中单独使用时,一切正常) C。该类的其余部分与任何其他CCSprite类相同。
//DragHandlingSprite.h
@interface DragHandlingSprite : CCSprite {
..........
}
@end
//DragHandlingSprite.m
@implementation DragHandlingSprite {
..............
}
-(void)onEnter{
self.userInteractionEnabled = YES;
..............
}
-(void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
............
}
-(void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event{
CGPoint touchLocation = [touch locationInNode:self.parent];
self.position = touchLocation;
}
-(void)touchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
.............
}
// MainScene.h
@interface MainScene : LongPressHandlingScene{
.............
}
+(MainScene *)scene;
@end
// MainScene.m
@implementation MainScene
+(MainScene) scene {
MainScene *scene = [self node];
return scene;
}
-(id) init {
if(!(self = [super init]))
return nil;
self.userInteractionEnabled = YES;
...............
NSArray *itemsArray = ProperlyPopulatedArrayFromSomewhereElse;
for(id obj in itemsArray){
if([obj isKindOfClass:[NSDictionary class]]){
NSDictionary *vDict = (NSDictionary *)obj;
float posX = [[vDcit objectForKey:@"posXKey"] floatValue];
float poxY = [[vDict objectForKey:@"posYKey"] floatValue];
NSString *name = [vDict objectForKey:@"imageName"];
DragHandlingSprite *newImage = [DragHandlingSprite spriteWithImageNamed:name];
newImage.name = name;
newImage.position = CGPointMake(posX, posY);
[self addChild:newImage];
}
@end
我将一个或多个“DragHandingSprites”添加到“LongPressHandlingScene”后我遇到的问题如下:
点击任何“DragHandlingSprite”一次有效。在第一个之后单击相同或任何其他“DragHandlingSprite”会使应用程序崩溃,并显示错误“:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary setObject:forKey:]: attempt to insert nil key'
LongPressRecognition 100%的工作时间,但只要单击一次,就会发生与上述相同的异常。
有什么想法吗?
提前致谢。
答案 0 :(得分:0)
对于那些可能偶然发现这个问题寻找答案的人来说,这就是我想出来的。
在正常情况下,UILongPressGestureRecognizer(可可)和onTouch事件(Cocos2d)可以共存而不会出现任何问题。一旦两者都在相同的“CCScene”中声明,所有它们各自的选择器/事件处理程序将在“触摸”生命周期中被调用。这通过允许运行所有基于触摸/手势的代码而导致我上面提到的错误。在我的例子中,一些事件处理程序正在删除UILongPRessGestureRecognizer操作选择器需要使用的信息,反之亦然,因此在某些时候尝试处理“nil”键并导致错误。
出于这个原因,我决定实现一个基于枚举的状态变量,该变量将跟踪应用当前所处的“触摸”状态,以防止代码执行不顺。
enum TouchStates {DRAG_BEGAN, DRAG_MOVED, DRAG_ENDED, LONG_TOUCH_BEGAN, LONG_TOUCH_ENDED, DEFAULT};
enum TouchStates touchState;
........
-(id)init{
................
UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longTouchAction:)];
............
}
-(void)longTouchAction:(UILongPressGestureRecognizer *)longTouch{
if(/*[touchState is the correct one to do something here]*/){
if(longTouch.state == UIGestureRecognizerStateBegan){
touchState = LONG_TOUCH_BEGAN;
.............
//DO WHAT'S NECESSARY HERE
.............
}
// Do something similar for the "UIGestureRecongizerEnded" flag
}
-(void)onTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
if(/*[touchState is the correct one to do something here]*/){
touchState = DRAG_BEGAN;
..............
//DO WHAT'S NECESSARY HERE
...............
}
// Do something similar for the onTouchMoved and onTouchEnded event handlers.