2011-09-09 9 views
9

En algún mantenimiento de un código de "dibujo en pantalla" multitáctil, me encontré con un error relativo a cómo las referencias a las instancias de toques deben establecerse entre toquesBegan: conEvent :, toquesMoved: conEvent: y toquesEnded: conEvent :.Cómo rastrear los toques de forma consistente entre los toques BeGo: y toquesEnded :?

El código utiliza un ejemplo NSDictionary para almacenar referencias de toques en touchesBegan: withEvent :, de la siguiente manera:

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

y los recupera en touchesEnded: withEvent: de esta manera:

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

En este último bit de código, valueFromDictionary pasa a ser ocasionalmente nulo, ya que la clave no es conocida por el diccionario. De vez en cuando, me refiero a aproximadamente el 1% del tiempo.

Ahora el contexto está establecido, mis preguntas son:

  1. Cualquier idea de por qué este código está libre de errores? No estoy seguro de por qué no funciona, especialmente debido a la muy baja frecuencia de los errores

  2. Some doc from Apple afirma que es una buena idea utilizar direcciones de los objetos UITouch como claves : pero significa el uso de objetos NSValue * en lugar de los objetos NSString * ( ) y, en consecuencia, utilizando CFDictionaryRef en lugar de NSDictionary debido a que UITouch no implementa el protocolo de copiado). ¿Por qué almacenar una representación en NSString de la dirección en lugar de la NSValue en sí misma no puede ser una solución fácil para poder usar NSDictionary? Actualización: Apple ha actualizado la página y eliminado el ejemplo de almacenamiento de un UITouch a través de un NSString y simplemente menciona la solución CFDictionaryRef que no es un objeto en absoluto.

me temo que estoy lejos de C y punteros cosas y necesitan ayuda para comprender la razón por la que hay un error en el código.

Respuesta

4

Cuando utiliza stringWithFormat para convertir la instancia de NSValue en una cadena, creo que básicamente está llamando [descripción de touchValue], lo que no estoy seguro garantiza un resultado consistente. Por ejemplo, ¿qué ocurre si la descripción incluye un puntero a la instancia de NSValue, como lo hacen muchos objetos? En ese caso, dos instancias de NSValue diferentes que almacenen el mismo puntero producirán claves de cadena diferentes.

Estaría interesado en ver lo que sucede cuando se ejecuta el siguiente código:

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]; 
} 

Esto nos dirá exactamente lo que está cambiando acerca de la clave. Pero si prefieres solo solucionar el problema que tienes, apuesto a que funcionaría si usaras el objeto NSValue como clave directamente, ya que cumple con el protocolo NSCopying. Básicamente, el puntero (UITouch *) es solo un número que identifica de forma única dónde se almacena la instancia de UITouch en la memoria. NSValue encapsula este número de la misma manera que lo haría NSNumber, por lo que podría pensarlo como una clave numérica en la matriz.Mientras el contacto sigue ocupando el mismo lugar en la memoria (ya que Apple sugiere que será), que debería funcionar perfectamente como una clave, y su código sería más simple:

(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]; 
} 

realmente no hay razón para limitarte a claves de cadena, a menos que necesite usar valor clave de codificación o serializar el diccionario a una lista de propiedades.

+0

He intentado con la solución NSValue pero tuve el mismo resultado que con NSString: funcionaba bien el 99% del tiempo, pero seguía siendo el 1% de los errores. Ahora supongo que es un error de Apple (el hecho de que la página que mencioné en mi pregunta acaba de actualizarse hace unos días es otra pista, incluso el personal de Apple no está seguro de este problema) O un problema de concurrencia entre el momento en que Puse los datos y obtengo los datos. –

-1

No utilice

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

para la clave. La mejor manera sería la creación de valor del puntero táctil como una clave

id key = touch; 

o si lo prefiere cadenas, utilice este caso:

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

La solución% x no puede funcionar: está almacenando el valor de un puntero en lugar de la dirección a la que apunta (en realidad me di cuenta de esto después de haberlo probado: el error aparece el 100% del tiempo en lugar del 1%) –

+0

Parece extraño. ¿Puede establecer puntos de interrupción en sus métodos 'touchesBegan' y 'touchesEnded' y comparar las direcciones de 'UITouch * touch' (y también compararlo con el valor guardado en la clave a través de @ "x")? Como sé, todos estos valores deben ser iguales. Uso el mismo método en mi aplicación y funciona. Verifique también que pase 'touch' pero no 'touchValue' a @ "x". – brigadir

4

Usted puede utilizar hash de UITouch propiedad tanto para ObjC y Swift. Es lo mismo con el mismo toque en varios eventos (Arriba, Abajo, Mover, etc.). Es un Int pero puede convertirlo a String

Cuestiones relacionadas