NSDefaultRunLoopMode frente a NSRunLoopCommonModes

114

Cada vez que intento descargar un archivo grande detrás UIScrollView, MPMapViewo algo así, el proceso de descarga se detiene tan pronto como toco la pantalla del iPhone. Afortunadamente, una publicación de blog increíble de Jörn sugiere una opción alternativa, usar NSRunLoopCommonModespara la conexión.

Eso me hace ver en detalle los dos modos, NSDefaultRunLoopMode y NSRunLoopCommonModes, pero el documento de Apple no explica amablemente, aparte de decir

NSDefaultRunLoopMode

El modo para tratar con fuentes de entrada distintas de los objetos NSConnection. Este es el modo de ciclo de ejecución más utilizado.

NSRunLoopCommonModes

Los objetos agregados a un ciclo de ejecución utilizando este valor como modo son monitoreados por todos los modos de ciclo de ejecución que han sido declarados como miembros del conjunto de modos "comunes"; consulte la descripción de CFRunLoopAddCommonMode para obtener más detalles.

CFRunLoopAddCommonMode

Las fuentes, temporizadores y observadores se registran en uno o más modos de ciclo de ejecución y solo se ejecutan cuando el ciclo de ejecución se ejecuta en uno de esos modos. Los modos comunes son un conjunto de modos de ciclo de ejecución para los que puede definir un conjunto de fuentes, temporizadores y observadores que comparten estos modos. En lugar de registrar una fuente, por ejemplo, en cada modo de ciclo de ejecución específico, puede registrarla una vez en el pseudomodo común del ciclo de ejecución y se registrará automáticamente en cada modo de ciclo de ejecución en el conjunto de modos comunes. Del mismo modo, cuando se agrega un modo al conjunto de modos comunes, cualquier fuente, temporizador u observador ya registrado en el pseudomodo común se agrega al modo común recién agregado.

¿Alguien puede explicar los dos en lenguaje humano?

Stkim1
fuente

Respuestas:

204

Un ciclo de ejecución es un mecanismo que permite que el sistema despierte subprocesos inactivos para que puedan administrar eventos asincrónicos. Normalmente, cuando ejecuta un hilo (con la excepción del hilo principal) hay una opción para iniciar el hilo en un ciclo de ejecución o no. Si el subproceso ejecuta algún tipo o operación de larga duración sin interacción con eventos externos y sin temporizadores, no necesita un ciclo de ejecución, pero si su subproceso necesita responder a eventos entrantes, debe adjuntarse a un ciclo de ejecución para despierta el hilo cuando llegan nuevos eventos. Este es el caso de los NSURLConnectionhilos generados, ya que solo se despiertan en eventos entrantes (de la red).

Cada subproceso se puede asociar a varios ciclos de ejecución o se puede asociar a un ciclo de ejecución específico que se puede configurar para que funcione en diferentes modos. Un "modo de ciclo de ejecución" es una convención utilizada por el sistema operativo para establecer algunas reglas sobre cuándo entregar ciertos eventos o recopilarlos para entregarlos más tarde.

Por lo general, todos los bucles de ejecución se establecen en el "modo predeterminado", que establece una forma predeterminada de administrar los eventos de entrada. Por ejemplo: tan pronto como ocurra un evento de arrastrar el mouse (Mac OS) o tocar (en iOS), entonces el modo para este ciclo de ejecución se establece en seguimiento de eventos; esto significa que el hilo no se despertará en nuevos eventos de red, pero estos eventos se entregarán más tarde cuando finalice el evento de entrada del usuario y el ciclo de ejecución se establezca nuevamente en el modo predeterminado; obviamente, esta es una elección hecha por los arquitectos del sistema operativo para dar prioridad a los eventos del usuario en lugar de los eventos de fondo.

Si decide cambiar el modo de ciclo de ejecución para su NSURLConnectionsubproceso, utilizando scheduleInRunLoop:forModes:, entonces puede asignar el subproceso a un modo de ciclo de ejecución especial , en lugar del ciclo de ejecución predeterminado específico. El pseudo-modo especial llamado NSRunLoopCommonModeses utilizado por muchas fuentes de entrada, incluido el seguimiento de eventos. Por ejemplo, asignar NSURLConnectionla instancia de 'al modo común significa asociar sus eventos al "modo de seguimiento" además del "modo predeterminado". Una ventaja / desventaja de asociar subprocesos con NSRunLoopCommonModeses que el subproceso no será bloqueado por eventos táctiles.

Se pueden agregar nuevos modos a los modos comunes, pero esta es una operación de nivel bastante bajo.

Me gustaría cerrar agregando algunas notas:

  • Normalmente, necesitamos utilizar un conjunto de imágenes o miniaturas descargadas de la red con una vista de tabla. Podemos pensar que descargar estas imágenes de la red mientras se desplaza la vista de tabla podría mejorar la experiencia del usuario (ya que pudimos ver las imágenes mientras se desplaza), pero esto no es ventajoso ya que la fluidez del desplazamiento puede sufrir mucho. En este ejemplo con NSURLConnectionun ciclo de ejecución no se debe utilizar; sería mejor utilizar los UIScrollViewmétodos de delegado para detectar cuándo finaliza el desplazamiento y luego actualizar la tabla y descargar nuevos elementos de la red;

  • Puede considerar el uso de GCD, que le ayudará a "proteger" su código de problemas de gestión de bucle de ejecución. En el ejemplo anterior, puede considerar agregar sus solicitudes de red a una cola serial personalizada.

viggio24
fuente
9
Estimado Viggio24, muchas gracias por esta limpia y precisa explicación. Le pediría a Apple que incluyera su comentario en su guía de API. ;)
Stkim1
7
La respuesta de viggio24 es perfecta. Para aquellos interesados, señalaría que la Sesión 208 (Aplicaciones de red para iPhone OS, Parte 2) de WWDC 2010 contiene una introducción sobre los bucles de ejecución. Si te interesa echa un vistazo. Espero eso ayude.
Lorenzo B
19
Solo una nota para mí: NSRunLoopCommonModespermite un evento de temporizador mientras me desplazo UIScrollView. NSDefaultRunLoopModeevitar el temporizador mientras se desplaza.
eonil
2
Me pareció muy interesante el comentario sobre la actualización de la vista de desplazamiento, ya que menciona un tema muy desafiante. Solo para agregar más detalles sobre esto: cuando establece un modo para una NSURLConnection, esto solo afecta la ejecución de las devoluciones de llamada del delegado. Entiendo que actualizar scrollView aquí podría resultar en un problema de rendimiento, pero ¿por qué sucede esto? Si la respuesta es que la imagen debe cargarse en la memoria, puede hacerlo escribiendo en un contexto gráfico en el fondo y actualizar la capa del hilo principal de la vista después de hacer esto. ¿Suena esto razonable?
nebillo