2010-07-30 11 views
5

Estoy creando una aplicación de diccionario para iPhone que da resultado mientras los usuarios escriben. Yo uso hilos (NSThread) para actualizar UITableView para que el hilo principal no esté bloqueado.Actualice UITableView usando subprocesos

Sin embargo, un accidente ocurre cuando el UITableView pide a la fuente de datos para el número de filas (tableView: numberOfRowsInSection :) y vuelvo, por ejemplo, 10. A continuación, se solicita a la fuente de datos para las células 0-9 (tableView: cellForRowAtIndexPath :). Pero en el momento en que solicita la celda 7, la fuente de datos ya ha cambiado, y ahora solo tiene 5 filas, lo que causa un bloqueo.

Aquí es cómo resolver el problema:

creo un NSLock en el método init.

Y aquí es lo que la fuente de datos se parece a:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return [results count]; 
} 


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    static NSString *CellIdentifier = @"Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 
    } 

    [lock lock]; 
    if (indexPath.row < [results count]) { 
     cell.textLabel.text = [results objectAtIndex:indexPath.row]; 
    } 
    [lock unlock]; 

    return cell; 
} 

Y aquí está el código que utilizo para actualizar la tabla:

[tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]; 

Resuelve el problema de bloqueo completo. Sin embargo, creo que podría no ser eficiente porque la fuente de datos tiene que bloquearse/desbloquearse cada vez que se solicita una celda. Y el caso que mencioné arriba no sucede tan a menudo. ¿Alguien tiene una mejor idea de cómo resolver este problema de manera eficiente?

Muchas gracias!

+2

No debe actualizar la interfaz de usuario en otro hilo. – rickharrison

+0

Rick, tengo que buscar el resultado en otro hilo porque el método de búsqueda es bastante lento y no quiero que bloquee el hilo principal. ¿Podría explicar cómo puedo lograr eso sin usar otro hilo? – ifvc

+0

hacerlo más rápido.¿Por qué estás buscando? – mvds

Respuesta

2

¿Por qué usaría un hilo separado para esto? ¿Cuánto tiempo lleva la búsqueda? 0.1 segundos? ¿Cómo se compara eso con el tiempo que toma el usuario para dejar de escribir y mirar la pantalla?

¡No compliques demasiado las cosas! (Retomaré esto si la búsqueda lleva más de 0,7 segundos y no se puede optimizar ;-)

+0

Para ser honesto, toma alrededor de 0.2-0.3 segundos. (La búsqueda original con SQLite/FTS3 demora aproximadamente 0,5 segundos, por lo que la optimicé mediante el uso de texto sin formato y búsqueda binaria). Aunque es pequeña, cuando se combina con el tiempo necesario para actualizar la tabla, sigue siendo lo suficientemente grande como para dar me da la sensación de que el teclado es "pegajoso". – ifvc

+0

Así que está viendo unos registros de 1 m ... Me centraría en optimizar la búsqueda de datos, también beneficiará la experiencia del usuario. Por un lado, si un usuario escribe "b" no hay ninguna razón para cocinar la lista "b" completa inmediatamente. – mvds

+0

Lo intenté con SQLite y no importó, incluso si uso "LIMIT 1". Supongo que podría ser porque SQLite busca primero la lista completa, luego la ordena (aunque no utilizo ningún "ORDER BY"), y finalmente devuelve el resultado. Es por eso que cambié a la búsqueda binaria, por lo que puedo buscar los índices del límite inferior y el límite superior, luego consultar el resultado según sea necesario. – ifvc

4

No intente actualizar la interfaz de usuario desde una cadena de fondo. No funcionará.

+1

Es por eso que uso [tableView performSelectorOnMainThread: @selector (reloadData) withObject: nil waitUntilDone: NO]; y funciona (en el sentido de que ya no hay colisión). Pero me gustaría que funcione más rápido al no utilizar el bloqueo/desbloqueo cada vez que se solicita una celda. – ifvc

1

Solo para que haya una respuesta útil aquí, esta es mi respuesta a otra pregunta similar.

Sin tener que saber más acerca de su aplicación, creo que una de las mejores soluciones sería mantener la matriz en el hilo principal y volver a enviarla cada vez que otro hilo deba realizar un cambio. De esta manera:

dispatch_async(dispatch_get_main_queue(), ^{ 
       [array addObject:object]; 
       [tableView reloadData]; 
      }); 

Por supuesto, usted puede conseguir mucho más compleja con la API de despacho, pero sí manejar el bloqueo y todo para usted. Definitivamente más elegante que usar un NSLock. Sin embargo, solo funciona en iOS 4 o posterior.

Cuestiones relacionadas