首页 文章

如何在touchesBegan:和touchesEnded之间以一致的方式跟踪触摸:?

提问于
浏览
9

在某些多点触控“屏幕绘图”代码的维护中,我遇到了一个错误,相对于如何在touchesBegan:withEvent:,touchesMoved:withEvent:和touchesEnded:withEvent:之间设置对touches实例的引用 .

该代码使用NSDictionary实例来存储touchesBegan:withEvent:中的touches引用,如下所示:

for (UITouch *touch in touches]) {
    NSValue *touchValue = [NSValue valueWithPointer:touch];
    NSString *key = [NSString stringWithFormat:@"%@", touchValue];
    [myTouches setValue:squiggle forKey:key];
}

并以touchesEnded:withEvent检索它们:这样:

for (UITouch *touch in touches) {
    NSValue *touchValue = [NSValue valueWithPointer:touch];
    NSString *key = [NSString stringWithFormat:@"%@", touchValue];
    NSObject *valueFromDictionary = [myTouches valueForKey:key];
    [myTouches removeObjectForKey:key];
}

在最后一段代码中,valueFromDictionary恰好偶尔为nil,因为字典不知道密钥 . 偶尔,我的意思是大约1%的时间 .

现在上下文已经确定,我的问题是:

  • 知道为什么这个代码有问题吗?我不确定它为什么不起作用,特别是因为错误的频率非常低

  • Some doc from Apple声明使用UITouch对象的地址作为键是个好主意:但它意味着使用NSValue *对象而不是NSString *对象(因此使用CFDictionaryRef而不是NSDictionary,因为UITouch没有实现复制协议) . 如何存储地址的NSString表示而不是NSValue本身不能成为能够使用NSDictionary的简单解决方案? Update: Apple has updated the page and removed the example of storing a UITouch via a NSString and just mentions the not-object-at-all CFDictionaryRef solution.

我担心我离C和指针很远,需要帮助才能理解这段代码中存在错误的原因 .

3 回答

  • 4

    当你使用stringWithFormat将NSValue实例转换为字符串时,我相信你实际上是在调用[touchValue description],我不确定它是否保证一致的结果 . 例如,如果描述包含指向NSValue实例本身的指针,那么会有多少个对象呢?在这种情况下,存储完全相同指针的两个不同的NSValue实例将产生不同的字符串键 .

    我有兴趣看看运行以下代码时会发生什么:

    for (UITouch *touch in touches) {
      NSValue *touchValue = [NSValue valueWithPointer:touch];
      NSString *key = [NSString stringWithFormat:@"%@", touchValue];
      NSObject *valueFromDictionary = [myTouches valueForKey:key];
    
      if (valueFromDictionary == nil) {
        NSLog(@"%@", [myTouches allKeys]);
        NSLog(@"%@", key);
      }
    
      [myTouches removeObjectForKey:key];
    }
    

    这将告诉我们关于密钥的确切变化 . 但是如果你只是想解决你遇到的问题,我敢打赌,如果你直接使用NSValue对象作为密钥,它会起作用,因为它确实符合NSCopying协议 . 本质上,指针(UITouch *)只是一个唯一标识UITouch实例存储在内存中的位置的数字 . NSValue以与NSNumber相同的方式封装此数字,因此您可以将其视为数组中的数字键 . 只要触摸继续占据内存中的相同位置(如Apple建议的那样),它应该完美地作为键,并且您的代码将更简单:

    (的touchesBegan:withEvent :)

    for (UITouch *touch in touches]) {
      NSValue *key = [NSValue valueWithPointer:touch];
      [myTouches setValue:squiggle forKey:key];
    }
    

    (touchesEnded:withEvent :)

    for (UITouch *touch in touches) {
      NSValue *key = [NSValue valueWithPointer:touch];
      NSObject *valueFromDictionary = [myTouches valueForKey:key];
      [myTouches removeObjectForKey:key];
    }
    

    除非您需要使用键值编码或将字典序列化到属性列表,否则没有理由将自己局限于字符串键 .

  • -1

    您可以为ObjC和Swift使用 hashUITouch 属性 . 对于多个事件(向上,向下,移动等)的相同触摸,它是相同的 . 它是 Int 但您可以将其转换为 String

  • 4

    不要用

    NSString *key = [NSString stringWithFormat:@"%@", touchValue];
    

    为了钥匙 . 最好的方法是将触摸指针值设置为键

    id key = touch;
    

    或者如果您更喜欢字符串,请使用以下情况:

    NSString *key = [NSString stringWithFormat:@"%x", touch]; // %x prints hex value of touch
    

相关问题