2011-09-09 10 views
9

In alcune operazioni di manutenzione di alcuni codici "disegno su schermo" multitouch, ho incontrato un bug relativo a come i riferimenti ai tocchi devono essere impostati tra i touchBegan: withEvent :, touchMoved: withEvent: and touchEnded: withEvent :.Come tracciare i tocchi in modo coerente tra i touchBegan: e toccaEnded :?

Il codice utilizza un'istanza NSDictionary per memorizzare i riferimenti di tocchi in touchesBegan: withEvent :, come segue:

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

E li recupera in touchesEnded: withEvent: in questo modo:

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

In questo ultimo bit di codice, valueFromDictionary capita di essere ogni tanto zero, in quanto la chiave non è conosciuta dal dizionario. Occasionalmente intendo circa l'1% delle volte.

Ora il contesto è impostato, le mie domande sono:

  1. Qualsiasi idea del perché questo codice è bacato? Io non sono sicuro perché non funziona, soprattutto a causa della bassissima frequenza di errori

  2. Some doc from Apple afferma che sia una buona idea quella di utilizzare gli indirizzi degli oggetti come chiavi UITouch : ma significa usare NSValue * oggetti piuttosto che oggetti NSString * ( e di conseguenza utilizzando CFDictionaryRef anziché NSDictionary a causa del fatto che UITouch non implementa il protocollo di copia). Come mai memorizzare una rappresentazione NSString dell'indirizzo anziché lo stesso NSValue non può essere una soluzione facile per poter utilizzare NSDictionary? Aggiornamento: Apple ha aggiornato la pagina e rimosso l'esempio di memorizzare un UITouch tramite un NSString e menziona semplicemente la soluzione CFDictionaryRef non-object-at-all.

ho paura sono lontano da C e puntatori roba e hanno bisogno di aiuto per capire la ragione c'è un bug in questo codice.

risposta

4

Quando si utilizza stringWithFormat per convertire l'istanza NSValue in una stringa, credo che si stia essenzialmente chiamando [descrizione touchValue], che non sono sicuro garantisce un risultato coerente. Ad esempio, cosa succede se la descrizione includeva un puntatore all'istanza NSValue stessa, come fanno molti oggetti? In tal caso, due diverse istanze di NSValue che memorizzano lo stesso puntatore stesso produrranno chiavi di stringa diverse.

Sarei interessato a vedere cosa succede quando si esegue il codice seguente:

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

Questo ci avrebbe detto esattamente che cosa sta cambiando sulla chiave. Ma se preferisci semplicemente risolvere il problema che stai avendo, scommetto che funzionerebbe se tu usassi direttamente l'oggetto NSValue come chiave, poiché è conforme al protocollo NSCopying. In sostanza, il puntatore (UITouch *) è solo un numero che identifica in modo univoco dove è archiviata l'istanza UITouch in memoria. NSValue incapsula questo numero allo stesso modo di NSNumber, quindi potresti considerarlo come una chiave numerica nell'array.Finché il tocco continua ad occupare la stessa posizione nella memoria (come di Apple suggerisce che sarà), dovrebbe funzionare perfettamente come una chiave, e il tuo codice sarebbe più semplice:

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

non c'è davvero alcun motivo di limitare se stessi per chiavi stringa, a meno che non è necessario utilizzare la codifica di valori-chiave o serializzare il dizionario a un elenco di proprietà.

+0

Ho provato la soluzione NSValue ma ho avuto lo stesso risultato di NSString: funziona ben il 99% delle volte ma ancora questo 1% di bug. Ora presumo che sia un bug di Apple (il fatto che la pagina che stavo citando nella mia domanda è stata appena aggiornata qualche giorno fa è un altro indizio anche se il personale Apple non è sicuro di questo problema) O un problema di concorrenza tra il momento in cui Inserisco i dati e ottengo i dati. –

-1

Non utilizzare

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

per la chiave. Il modo migliore sarebbe quella di impostare il valore del puntatore tocco come chiave

id key = touch; 

o se si preferisce stringhe, utilizzare questo caso:

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

La soluzione% x non può funzionare: stai memorizzando il valore di un puntatore piuttosto che l'indirizzo a cui stai puntando (l'ho effettivamente realizzato dopo averlo testato: il bug appare il 100% delle volte anziché l'1%) –

+0

Sembra strano. Puoi impostare i punti di interruzione nei tuoi metodi "tocca Began" e "tocca Ended" e confrontare gli indirizzi di "UITouch * touch" (e anche confrontarlo con il valore salvato in chiave tramite @ "x")? Come so tutti questi valori devono essere uguali. Io uso lo stesso metodo nella mia app e funziona. Si prega di controllare anche che si passa 'touch', ma non 'touchValue' a @ "x". – brigadir

4

È possibile utilizzare hash di UITouch immobili sia per objC e Swift. È lo stesso per lo stesso tocco su più eventi (Su, Giù, Sposta, ecc.). Si tratta di unma è possibile convertirlo in String

Problemi correlati