簡體   English   中英

如何在 touchesBegan: 和 touchesEnded: 之間以一致的方式跟蹤觸摸?

[英]How to track touches in a consistent way between touchesBegan: and touchesEnded:?

在一些多點觸控“在屏幕上繪圖”代碼的維護中,我遇到了一個關於如何在 touchesBegan:withEvent:、touchesMoved:withEvent: 和 touchesEnded:withEvent: 之間設置對 touches 實例的引用的錯誤。

代碼使用 NSDictionary 實例在 touchesBegan:withEvent: 中存儲觸摸的引用,如下所示:

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% 的時間。

現在上下文已設置,我的問題是:

  1. 知道為什么這段代碼有問題嗎? 我不確定為什么它不起作用,特別是因為錯誤頻率非常低

  2. Apple 的一些文檔指出,使用 UITouch 對象的地址作為鍵是個好主意 :但這意味着使用 NSValue* 對象而不是 NSString* 對象( 因此使用 CFDictionaryRef 而不是 NSDictionary,因為 UITouch 沒有實現復制協議)。 為什么存儲地址的 NSString 表示而不是 NSValue 本身不是能夠使用 NSDictionary 的簡單解決方案? 更新:Apple 已經更新了頁面並刪除了通過 NSString 存儲 UITouch 的示例,並且只提到了 not-object-at-all CFDictionaryRef 解決方案。

恐怕我遠離 C 和指針的東西,需要幫助來理解這段代碼中存在錯誤的原因。

您可以對 ObjC 和 Swift 使用UITouch屬性的hash 對於跨多個事件(向上、向下、移動等)的相同觸摸也是如此。 它是一個Int但你可以將它轉換為String

當您使用 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];
}

真的沒有理由將自己局限於字符串鍵,除非您需要使用鍵值編碼或將字典序列化為屬性列表。

這對我有用:

-(NSString * ) keyForTouch:(UITouch *) touch {
    return [NSString stringWithFormat:@"%lu", (unsigned long)[touch hash]];
}

//Example method, how to use:

-(UIView *) getViewForTouch:(UITouch*) touch{
    NSString * key = [self keyForTouch:touch];
    return [self.myDictionary objectForKey:key];
}

不要使用

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

為關鍵。 最好的方法是將觸摸指針值設置為鍵

id key = touch;

或者,如果您更喜歡字符串,請使用這種情況:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM