¿Cómo puedo controlar la frecuencia de los eventos de cambio de valor de UISlider?

Estoy escribiendo una aplicación para iPhone que utiliza dos controles deslizantes para controlar los valores que se envían mediante coreBluetooth. Si muevo los controles deslizantes rápidamente, un valor se congela en el receptor, presumiblemente porque los eventos de cambio de valor se activan con tanta frecuencia que los comandos de escritura se acumulan y finalmente se desechan. ¿Cómo puedo asegurarme de que los eventos no se activen con demasiada frecuencia?

Edit:

Aquí hay una aclaración del problema; la conexión bluetooth envía comandos cada 105ms. Si el usuario genera un montón de eventos durante ese tiempo, parece que se ponen en cola. Me gustaría desechar los valores generados entre los eventos de conexión y simplemente enviar uno cada 105 ms.

Esto es básicamente lo que estoy haciendo ahora mismo:

-(IBAction) sliderChanged:(UISlider *)sender{

  static int8_t value = 0;
  int8_t new_value = (int8_t)sender.value;

  if ( new_value > value + threshold || new_value < value - threshold ) {
    value = new_value;  
    [btDevice writeValue:value];
  }
}

Lo que estoy preguntando es cómo implementar algo como

-(IBAction) sliderChanged:(UISlider *)sender{

  static int8_t value = 0;

  if (105msHasPassed) {
    int8_t new_value = (int8_t)sender.value;

    if ( new_value > value + threshold || new_value < value - threshold ) {
      value = new_value;  
      [btDevice writeValue:value];
    }
  }
}

preguntado el 04 de julio de 12 a las 08:07

3 Respuestas

Supongo que tiene sentido seguir activándolos... Lo que yo haría en su caso sería verificar el delta entre el valor actual y el valor anterior. Por ejemplo:

  • Valor actual -> 5.
  • Siguiente valor -> 6.
  • Delta 1

Solo un poco de pseudocódigo:

if(delta>5){
 //do your stuff
}

Probablemente no haría esto, pero:

-(void)sliderValueChanged:(UISlider *)sender{
    [self performSelector:@selector(removeAction:) withObject:sender afterDelay:0.3];
    // Do your stuff
}

- (void)removeAction:(UISlider *)sender{
    [sender removeTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];    

    [self performSelector:@selector(addAction:) withObject:sender afterDelay:0.3];
}

- (void)addAction:(UISlider *)sender{
    [mySlider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];   
}

No probé esto, pero creo que entiendes la idea.

Respondido 05 Jul 12, 08:07

¡Gracias Jackboy! Tengo un filtrado de umbral, desafortunadamente habrá una compensación entre la precisión y la velocidad usando solo este método. Si de alguna manera pudiera controlar el período de tiempo entre los eventos, aún podría permitir movimientos precisos si son lentos. - Albert

Como dijiste; Probablemente no haría esto, pero lo intentaré, ¡gracias! - Albert

No lo haría porque realmente no me gusta... Una var delta tiene más sentido para mí. - rui peres

Intenté esto y funcionó como un medio para controlar la tasa de paquetes. Sin embargo, no me siento muy cómodo con eso y obtuve mejores resultados al recortar otras partes de mi código, por lo que el problema probablemente no fue demasiados paquetes en primer lugar, sino muy pocos. ¡Gracias por mostrarme esto! - Albert

Podría complicarse y filtrar la entrada del control deslizante en función de alguna marca de tiempo o si la diferencia entre el valor nuevo y el valor anterior es mayor que algún umbral.

Una forma más sencilla sería usar un evento diferente: touchEnded. De esa manera, solo está enviando un valor final y no todos los valores intermedios.

Puede que no sea apropiado para su aplicación, pero no está del todo claro lo que debe hacer.

Respondido 04 Jul 12, 08:07

Perdón por no estar claro, necesito enviar valores continuos, pero a una tasa específica. Voy a editar en algunos detalles más! - Albert

Solo una idea, pero lo que podría hacer es no enviar el evento de cambio de valor. Puede almacenar el valor de la última transmisión en una variable, luego podría tener un temporizador ejecutándose en segundo plano que verifique si el último valor enviado es diferente al valor actual del control deslizante, si es así, envíe el nuevo valor. El temporizador se puede configurar para que se dispare cada 105 ms y solo enviará un valor cada 105 ms si el nuevo valor es diferente al último valor enviado.

Respondido 04 Jul 12, 10:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.