Когда вы используете stringWithFormat для преобразования экземпляра NSValue в строку, я полагаю, что вы, по сути, вызываете [описание touchValue], которое, я не уверен, гарантирует согласованный результат. Например, что если в описание включен указатель на сам экземпляр 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];
}
На самом деле нет причин ограничивать себя строковыми ключами, если только вам не нужно использовать кодирование значения ключа или сериализовать словарь в список свойств.