¿Debo usar un subproceso de fondo de mis acciones de interfaz de usuario?
-
05-10-2019 - |
Pregunta
Fondo
-
Tengo una
NSOutlineView
que muestra TrainingGroup entidades. -
Cada TrainingGroup representa una carpeta en el equipo local.
-
El
NSOutlineView
se une a unNSTreeController
con un predicado ha podido recuperar deIsTrained == 0
-
Cada TrainingGroup se puede asignar a un proyecto.
-
Cada TrainingGroup tiene muchas TrainingEntries que muestran un tiempo trabajó en ese archivo.
-
Cuando se asigna el TrainingGroup a un proyecto, el
IsTrained
se establece enYES
. -
En Asignar a un proyecto, todos los descendientes son también asignó a ese proyecto y de sus bienes
IsTrained
se establece enYES
también. -
Proyecto columna se une a la propiedad
projectTopLevel
.
Ejemplo
Todo el aspecto de árbol como este:
Name Project IsTrained
Users nil NO
John nil NO
Documents nil NO
Acme Project Acme Project YES
Proposal.doc Acme Project YES
12:32-12:33 Acme Project YES
13:11-13:33 Acme Project YES
... etc
Budget.xls Acme Project YES
Big Co Project Big Co Project YES
Deadlines.txt Big Co Project YES
Spec.doc Big Co Project YES
New Project nil NO
StartingUp.doc nil NO
Personal Stuff Personal YES
MyTreehouse.doc Personal YES
Movies nil NO
Aliens.mov nil NO
StepMom.mov nil NO
Y el NSOutlineView sólo se vería así:
Users nil NO
John nil NO
Documents nil NO
New Project nil NO
StartingUp.doc nil NO
Movies nil NO
Aliens.mov nil NO
StepMom.mov nil NO
Si ha asignado Películas de personal, la vista sería ahora el siguiente aspecto:
Users nil NO
John nil NO
Documents nil NO
New Project nil NO
StartingUp.doc nil NO
Código
TrainingGroup.m
-(void)setProjectTopLevel:(JGProject *)projectToAssign {
[self setProjectForSelf:projectToAssign];
[self setProjectForChildren:projectToAssign];
}
-(void)setProjectForSelf:(JGProject *)projectToAssign {
[self setProject:projectToAssign];
}
-(void)setProjectForChildren:(JGProject *)projectToAssign {
for (TrainingGroup *thisTrainingGroup in [self descendants]) {
[thisTrainingGroup setProject:projectToAssign];
if(projectToAssign != nil) {
[thisTrainingGroup setIsTrainedValue:YES];
} else {
[thisTrainingGroup setIsTrainedValue:NO];
}
// Other code updating rules.
}
}
-(JGProject *)projectTopLevel {
return [self project];
}
-(NSSet *)untrainedChildren {
// Code that loops through all children returning those
// whose isTrained is NO. Omitted for brevity.
}
El problema
Como se puede ver arriba, estoy corriendo todo el código de asignación del proyecto en el hilo principal actualmente.
Cuando hay cientos de entradas de tiempo dentro de cada carpeta, mi aplicación deja de responder.
Posibles soluciones
1 Modal barra de progreso
El enfoque
- Ejecutar asignación del proyecto en un subproceso en segundo plano en el contexto separado.
- combinación de datos básicos del uso estándar en contexto principal cuando haya terminado.
- bloques A hoja modales cualquier actividad adicional hasta que la asignación proyecto ha terminado.
The Good
- El usuario recibe información inmediata sobre lo que está sucediendo.
- La aplicación sigue siendo sensible.
The Bad
- El usuario no puede hacer nada hasta que la asignación actual ha terminado.
2 no Modal Spinner
El enfoque
- Ejecutar asignación del proyecto en un subproceso en segundo plano en el contexto separado.
- combinación de datos básicos del uso estándar en contexto principal cuando haya terminado.
- Mostrar el progreso spinner junto grupo de entrenamiento, lo que indica que está ocupado.
- sobre la asignación de meta, el grupo de entrenamiento desaparece de la vista.
The Good
- se está procesando, el usuario puede hacer otras cosas mientras que su última acción
- La aplicación sigue siendo sensible. Un poco. Véase más abajo.
The Bad
- En las pruebas, he visto una congelación de hasta 3 segundos cuando el contexto de fondo se fusiona en el marco principal.
- La vista podría actualizar en el medio del usuario haciendo otra cosa, lo que podría ser molesto.
- Deshacer sería difícil de implementar.
3 Ocultar
El enfoque
- arriba, excepto el grupo de entrenamiento se retira en Asignar, y está dispuesto a ser "en curso" hasta que haya terminado de asignar.
Bueno y Malo
- Igual que el anterior, excepto en el orden de los grupos de entrenamiento permanecería predicatable.
- Todavía grande congelación en la parte posterior de combinación en contexto principal.
4 Mejorar el rendimiento
El enfoque
- Mantenga el código tal como es, se ejecuta en el hilo principal.
- Mejorar el rendimiento por lo que incluso con miles de entradas, la vista sólo se congela durante medio segundo como máximo
The Good
- Aplicación sigue siendo sensible.
- Deshacer, sigue siendo fácil.
- Arquitectura sigue siendo sencilla.
The Bad
- A mi entender, en contra de las recomendaciones de Apple - procesamiento intensivo no se debe hacer en el hilo principal
- ¿Puedo conseguir el suficiente rendimiento bueno? Desconocido.
Mis preguntas
Hasta donde puedo ver, ninguna de las opciones anteriores son ideales.
1. ¿Cuál es la mejor opción?
2. ¿Hay otras opciones?
3. ¿Qué podía mejorar mi enfoque?
Solución
- I actualizaría en un subproceso en segundo plano (Nº 2)
- Se puede desactivar la entrada del usuario siempre en las secciones de la ventana, y mostrar un mensaje de carga.
- Fácil de decir - ir a través de todo el código, y asegúrese de que está haciendo el menor número de llamadas necesarias, y que no se llama a las funciones innecesarias. También puede ejecutar algunas operaciones de larga duración en hilos separados, y luego ser notificado cuando termina de acción, por lo que puede procesar otras cosas mientras que la operación continúa.