开始触摸的次数不等于完成触摸的次数

我有以下代码用于testing目的:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self customTouchHandler:touches]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [self customTouchHandler:touches]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [self customTouchHandler:touches]; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [self customTouchHandler:touches]; } - (void)customTouchHandler:(NSSet *)touches { for(UITouch* touch in touches){ if(touch.phase == UITouchPhaseBegan) touchesStarted++; if(touch.phase == UITouchPhaseEnded || touch.phase == UITouchPhaseCancelled) touchesFinished++; } NSLog(@"%d / %d", touchesStarted, touchesFinished); } 

我想,当屏幕上没有触摸, touchesStarted应该总是等于touchesFinished ,但我有一个很奇怪的输出:

 2014-04-16 13:44:27.780 App[5925:60b] 2 / 0 2014-04-16 13:44:27.911 App[5925:60b] 2 / 1 

我用两个手指按下屏幕,然后几乎(但不是)在同一时间释放它们。

我错过了什么吗? 为我的视图启用了多个触摸。 顺便说一句,视图是SKView和代码属于我的自定义SKScene

UPDATE

许多人不能重现这种奇怪的行为,我准备了一个示例Xcode项目: https : //www.dropbox.com/s/qmgxka1gtgwquio/TapTest.zip

尝试多次同时用两根手指敲击。 当你移开手指时, touchesStarted必须等于touchesEnded ,对吧? 但他们不是。 这是我的输出:

 2014-04-24 12:49:06.359 TapTest[8207:60b] 1 / 0 2014-04-24 12:49:06.376 TapTest[8207:60b] 2 / 0 2014-04-24 12:49:06.458 TapTest[8207:60b] 2 / 0 2014-04-24 12:49:06.460 TapTest[8207:60b] 2 / 1 2014-04-24 12:49:06.491 TapTest[8207:60b] 2 / 2 2014-04-24 12:49:07.325 TapTest[8207:60b] 3 / 2 2014-04-24 12:49:07.342 TapTest[8207:60b] 4 / 2 2014-04-24 12:49:07.408 TapTest[8207:60b] 4 / 2 2014-04-24 12:49:07.410 TapTest[8207:60b] 4 / 3 2014-04-24 12:49:07.426 TapTest[8207:60b] 4 / 3 2014-04-24 12:49:07.441 TapTest[8207:60b] 4 / 4 2014-04-24 12:49:07.842 TapTest[8207:60b] 6 / 4 2014-04-24 12:49:07.925 TapTest[8207:60b] 6 / 4 2014-04-24 12:49:07.941 TapTest[8207:60b] 6 / 5 2014-04-24 12:49:08.042 TapTest[8207:60b] 8 / 5 2014-04-24 12:49:08.125 TapTest[8207:60b] 8 / 6 2014-04-24 12:49:08.259 TapTest[8207:60b] 9 / 6 2014-04-24 12:49:08.293 TapTest[8207:60b] 9 / 6 2014-04-24 12:49:08.308 TapTest[8207:60b] 9 / 7 2014-04-24 12:49:08.425 TapTest[8207:60b] 10 / 7 2014-04-24 12:49:08.442 TapTest[8207:60b] 11 / 7 2014-04-24 12:49:08.444 TapTest[8207:60b] 11 / 7 2014-04-24 12:49:08.492 TapTest[8207:60b] 11 / 8 2014-04-24 12:49:08.575 TapTest[8207:60b] 11 / 9 2014-04-24 12:49:08.642 TapTest[8207:60b] 12 / 9 2014-04-24 12:49:08.659 TapTest[8207:60b] 13 / 9 2014-04-24 12:49:08.660 TapTest[8207:60b] 13 / 9 2014-04-24 12:49:08.692 TapTest[8207:60b] 13 / 9 2014-04-24 12:49:08.694 TapTest[8207:60b] 13 / 10 2014-04-24 12:49:08.708 TapTest[8207:60b] 13 / 10 2014-04-24 12:49:08.741 TapTest[8207:60b] 13 / 11 2014-04-24 12:49:08.792 TapTest[8207:60b] 14 / 11 2014-04-24 12:49:08.809 TapTest[8207:60b] 15 / 11 2014-04-24 12:49:08.810 TapTest[8207:60b] 15 / 11 2014-04-24 12:49:08.890 TapTest[8207:60b] 15 / 11 2014-04-24 12:49:08.892 TapTest[8207:60b] 15 / 12 2014-04-24 12:49:08.908 TapTest[8207:60b] 15 / 13 2014-04-24 12:49:09.042 TapTest[8207:60b] 17 / 13 2014-04-24 12:49:09.141 TapTest[8207:60b] 17 / 14 2014-04-24 12:49:09.242 TapTest[8207:60b] 19 / 14 2014-04-24 12:49:09.341 TapTest[8207:60b] 19 / 14 2014-04-24 12:49:09.358 TapTest[8207:60b] 19 / 15 2014-04-24 12:49:09.441 TapTest[8207:60b] 21 / 15 2014-04-24 12:49:09.525 TapTest[8207:60b] 21 / 15 2014-04-24 12:49:09.542 TapTest[8207:60b] 21 / 15 2014-04-24 12:49:09.559 TapTest[8207:60b] 21 / 16 2014-04-24 12:49:09.608 TapTest[8207:60b] 22 / 16 2014-04-24 12:49:09.625 TapTest[8207:60b] 23 / 16 2014-04-24 12:49:09.626 TapTest[8207:60b] 23 / 16 2014-04-24 12:49:09.708 TapTest[8207:60b] 23 / 16 2014-04-24 12:49:09.709 TapTest[8207:60b] 23 / 17 2014-04-24 12:49:09.774 TapTest[8207:60b] 23 / 18 2014-04-24 12:49:09.810 TapTest[8207:60b] 24 / 18 2014-04-24 12:49:09.826 TapTest[8207:60b] 25 / 18 2014-04-24 12:49:09.828 TapTest[8207:60b] 25 / 18 2014-04-24 12:49:09.908 TapTest[8207:60b] 25 / 18 2014-04-24 12:49:09.909 TapTest[8207:60b] 25 / 19 2014-04-24 12:49:09.974 TapTest[8207:60b] 25 / 20 2014-04-24 12:49:09.992 TapTest[8207:60b] 26 / 20 2014-04-24 12:49:10.026 TapTest[8207:60b] 27 / 20 2014-04-24 12:49:10.027 TapTest[8207:60b] 27 / 20 2014-04-24 12:49:10.091 TapTest[8207:60b] 27 / 20 2014-04-24 12:49:10.094 TapTest[8207:60b] 27 / 21 2014-04-24 12:49:10.125 TapTest[8207:60b] 27 / 22 

也有这个问题。

只有在这个时刻我发现基于观察触摸阶段的解决scheme:

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"Began %lu of %lu", [touches count], [event.allTouches count]); for (UITouch *touch in touches) { [touch addObserver:self forKeyPath:@"phase" options:0 context:nil]; } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"Ended %lu of %lu", [touches count], [event.allTouches count]); } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([object isKindOfClass:[UITouch class]]) { UITouch *touch = object; NSLog(@"Touch %lu phase: %ld", (unsigned long)[touch hash], [touch phase]); if (touch.phase == UITouchPhaseEnded || touch.phase == UITouchPhaseCancelled) { NSLog(@"Touch %lu ended", (unsigned long)[touch hash]); [touch removeObserver:self forKeyPath:@"phase"]; } } } 

看来这是SKView的touchesBegan:方法中的一个错误。 据我所知,Apple正在使用一个字典将每个UITouch与触摸方法应该被转发的对象相关联。 从我的testing看来,如果有多个触摸同时开始,只有其中一个触摸被添加到字典中。 因此,您的场景将永远不会收到触摸相关的方法调用其他触摸,这就是为什么你看到touchesStarted和touchesFinished之间的区别。

如果您inheritanceSKView并覆盖touchesBegan:方法,则您的场景应该获得正确的调用。

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch *touch in touches) { NSSet *newSet = [NSSet setWithObject:touch]; [super touchesBegan:newSet withEvent:event]; } } 

这解决了我的问题,但可能会有多次调用超级方法的一些副作用。

无法评论,所以会在这里回答。 你打印所有这样的处理程序,也许这有助于:

 - (void)customTouchHandler:(NSSet *)touches { static int handlerCounter = 0; handlerCounter++; for(UITouch* touch in touches){ NSLog(@"%d: %d", handlerCounter, touch.phase); if(touch.phase == UITouchPhaseBegan) touchesStarted++; if(touch.phase == UITouchPhaseEnded || touch.phase == UITouchPhaseCancelled) touchesFinished++; } NSLog(@"%d / %d", touchesStarted, touchesFinished); } 

是否有可能在obj-c中切换(touch.phase)? 如果评估正确,则在第二个“或”中,请尝试使用括号。

如果您使用多个手指,则应包含self.view.multipleTouchEnabled = YES; 在你的init

我对你提供的代码进行了一些广泛的testing,唯一一次数字不匹配的是当一根或两根手指的组合都非常快速地进行粘贴时。 在这种情况下,iOS会丢失跟踪当前状态的联系人。

这与当一个精灵在另一个精灵上快速上下跳动非常相似,这有时在didBeginContact中导致错误的接触状态。

目前没有办法使用多个触摸来解决这个问题。 如果你使用一个单一的触摸,你的计数将永远(至less在我的testing)匹配。

我之前有同样的问题( touchesEnded:withEvent:未被调用 )。

我的testing显示,被激活的时间并不是被称为100%的时间。 我的解决scheme:将四个触摸处理方法放在AppDelegate.m文件中,并将触摸转发到您的视图控制器。 我不知道为什么这样做,但我没有任何问题后,这样做。