
Cómo evitar problemas de rendimiento con el preajuste Core Animation, qué usar para rastrear secciones de código y con qué funciones reducir la proporción de operaciones computacionales en la aplicación del 26% al 0.6%: lea la segunda parte del artículo basado en los materiales del informe de Luke Parham en la conferencia MBLT DEV del año pasado . La primera parte del artículo está disponible aquí .
Debajo del gato, no solo consejos útiles, sino también los últimos boletos anticipados para MBLT DEV 2018: puede comprarlos solo hoy.
Animación central
Core Animation (CA) es un ajuste preestablecido en el generador de perfiles que utiliza mediciones FPS (cuadros por segundo) para ver si las animaciones se retrasan o no. A menudo, incluso si se encuentran áreas problemáticas de la aplicación, persisten las dificultades de rendimiento. La razón es que cuando se trabaja con marcos de UI, se usa UIView, pero se crea una instancia de CATransaction bajo el capó (o el sistema lo hace por sí mismo), y todas estas instrucciones se envían al servidor para su procesamiento. El servidor para la representación es responsable de crear la animación. Si una animación se realiza utilizando una UIView, por ejemplo, el método de clase animate(withDuration:animations:)
, es procesado por el servidor de renderizado, que se considera un hilo separado y funciona con todas las animaciones en la aplicación.
Puede hacer que el servidor de procesamiento funcione lentamente para que no aparezca en Time Profiler, pero aún así ralentizará la aplicación. Así es como se ve:


En la parte superior está el sensor de velocidad de fotogramas. A continuación se muestra la parte más importante: opciones de depuración. Hay dos parámetros clave pero fáciles de configurar. El primero es color blended layers
. Arreglarlo es bastante simple. De hecho, incluso surgen problemas en iMessage, la aplicación favorita de Apple.

El rojo indica áreas con un fondo blanco. Se superponen con otro fondo blanco y, por alguna razón, parecen transparentes. Resulta que el programa mezcla estos colores entre sí: blanco con blanco, y el resultado es nuevamente blanco. Como resultado, por cada píxel que está marcado en rojo, se realizan cálculos adicionales que no aportan ningún beneficio: se obtiene un fondo blanco.
Regla # 3
Haga que las capas sean opacas siempre que sea posible, siempre que tengan los mismos colores que se superponen. La capa tiene la propiedad de opacity
, que debe establecerse en unit. Compruebe siempre que el color de fondo esté configurado y que sea opaco.

Representación fuera de pantalla
La siguiente opción es la representación fuera de pantalla. Si habilita esta función, las secciones se resaltarán en amarillo.
La conveniencia de Core Animation es la capacidad de ver otras aplicaciones. Puede activar las opciones, iniciar la aplicación y ver qué está yendo mal. En la pantalla en Instagram en la parte superior hay pequeños círculos amarillos en los que se muestran las historias del usuario.

Por ejemplo, en iPhone 6s, se cargan bastante lentamente. Y si los mira en el iPhone 5 o en el viejo modelo de iPod, la descarga será aún más lenta. Esto se debe al hecho de que la representación dentro del sistema es mucho peor que la combinación alfa. Carga la GPU. Como resultado, el dispositivo tiene que realizar constantemente cálculos adicionales entre el procesador de gráficos y el procesador central, por lo que hay retrasos adicionales que se pueden evitar en la mayoría de los casos.
Regla n. ° 4
No use el parámetro cornerRadius
. El uso de viewLayer.cornerRadius
da viewLayer.cornerRadius
resultado la representación fuera de pantalla. En su lugar, puede usar la clase UIBezierPath
, así como algo similar a trabajar con CGBitMap, como era el caso de la decodificación JPEG antes. En este caso, se UIGraphics context
.

Este es otro método de instancia de la clase UIImage. Aquí puede establecer el tamaño y hacer esquinas redondeadas. Bezierpath
se utiliza para resaltar un área de imagen. Luego, el fragmento se devuelve desde el UIImageContext. Por lo tanto, obtenemos la imagen final con esquinas redondeadas en lugar de redondear los marcos en los que se insertará la imagen.

En el GIF - página de Twitter. Imagen mostrada en tiempo real. Se supone que la página se abre y proporciona información, pero el texto y otros elementos de la pantalla se procesaron fuera de la pantalla, por lo que las animaciones se mueven muy lentamente.
Regla # 5
La propiedad de la clase shouldRasterize del conjunto CALayer le permite almacenar en caché las texturas que se han renderizado. Mejor evitarlo. Si shouldRasterize
no se ha utilizado durante un cierto número de milisegundos, abandonará el caché y ofrecerá la representación de cada fotograma. Entonces esto crea más problemas que bien.
Acelerar
- Evite la representación fuera de la pantalla y la combinación de capas transparentes.
- Úselos solo cuando no pueda prescindir de ellos. El renderizado fuera de la pantalla aparece debido a la presencia de sombras, esquinas redondeadas, etc.
- Hacer imágenes opacas.
- No use cornerRadius, use curvas de Bezier.
- Cuando trabaje con texto, no use la propiedad layer.shadow, reemplácela con NSShadow.
Rastreo de actividad
El rastreo de actividad es similar a lo que hace Time Profiler, pero a menor escala. Le permite considerar los flujos y su interacción entre ellos.
Regla # 6
Use System Trace para rastrear períodos de tiempo para eventos específicos. Puede encontrar una forma de rastrear eventos o secciones de código y ver cuánto tiempo tardan en el trabajo real de la aplicación. System Trace proporciona información sobre lo que está sucediendo en el sistema:
- El "Sing Post" indica que algo importante está sucediendo.
- Las marcas son eventos únicos que vale la pena ver, por ejemplo, la aparición de una animación.
- Por el intervalo del evento, puede realizar un seguimiento de cuánto tarda la decodificación.

Entonces, el programa muestra cómo interactúa el código con el resto del sistema.
En la pantalla hay un ejemplo de cómo crear una plantilla de rastreo del sistema:
- 1 - carga de imágenes
- 2 - decodificación de imagen
- 3 - animaciones de inclinación.
Debe agregar algunas opciones para comprender qué color resultará. Por lo general, se les asignan números, como 1 o 2, y se vuelven rojos o verdes, según la configuración. En Objective-C, debe escribir el comando #import
para kdebug_signpost
. En Swift, ya están disponibles.

Luego debe llamar a esta función kdebug_signpost
o kdebug_signpost_start
y kdebug_signpost_end
.

Indicamos 3 eventos junto con los números que están escritos en el código, y un elemento clave para cada evento específico. El último número indica el color. Por ejemplo, 2 es rojo.
Los siguientes son eventos importantes, objetos especiales. Un diagrama simplificado se describe en el proyecto de prueba de Luke en Swift.
La captura de pantalla muestra cómo se verá cuando comience el rastreo. Al principio, cuando se inicia la aplicación, el programa no dará información, pero tan pronto como la aplicación se bloquee, veremos los cálculos.

La descarga de imágenes lleva unos 200 milisegundos. Luego viene la decodificación, que toma alrededor de 40 milisegundos. Es útil realizar un seguimiento de estos datos si hay muchas operaciones en la aplicación. Puede enumerar eventos en el programa y luego observar y recibir información sobre cuánto tiempo se requiere para su implementación y cómo interactúan entre sí.
Herramientas adicionales
En la pantalla: proyecto AR para el disparo en cámara lenta de un teléfono inteligente. La aplicación es similar a Snapchat. Utilizó el efecto de retoque fotográfico, y para cada cuadro, el 26.4% de todas las operaciones informáticas se gastaron en él. Debido a esto, la cámara estaba disparando lentamente, aproximadamente 10 fotogramas por segundo. Al estudiar, vemos que la línea superior hizo la mayor parte del trabajo. Ella era responsable de enviar datos activamente. Si examina las causas del hundimiento del rendimiento, notará que el punto es el uso intensivo de NSDispatchData
.

Esta subclase de NSData
solo recibe una secuencia de bytes utilizando el método getBytes
en un cierto intervalo y lo pasa a otra ubicación. Parece ser tan simple, sin embargo, todo lo que este método hace internamente toma el 18% del 26% de los cálculos.

Regla n. ° 1
Use
NSData
y
getBytes
. Esta es una operación simple en Objective-C, pero si causa problemas en el sistema, debe cambiar a una función de nivel inferior en el plano C. Dado que el problema es obtener valores flotantes, puede usar la función de memoria de copia. Con él, puede mover una pieza de datos a otra ubicación. Esto ahorra en gran medida la potencia informática del dispositivo.
NSData tiene muchas operaciones. En el ejemplo, el código fuente se resalta en rojo. Usando la función
getBytes
, puede traducir datos a números de coma flotante. El método para copiar la memoria es casi el mismo. Es bastante simple y realiza un orden de magnitud menos operaciones.

Si cambia el enfoque y vuelve a iniciar la aplicación, se puede ver que el porcentaje de operaciones computacionales dedicadas a cambiar la foto disminuyó del 26% al 0.6%. Y esto se debe al cambio de una sola línea de código sobre la copia de memoria. La velocidad de fotogramas ha aumentado significativamente.

Regla # 2
Evite la superposición de píxeles entre sí al crear una aplicación que tenga renderizado.
En la mayoría de los casos, esto ocurrirá a una frecuencia superior a 60 cuadros por segundo. Con CADisplayLink
, puede ralentizar la actualización de la interfaz de usuario. Hay un parámetro PreferFramesPerSecond. Se aplica solo a iOS 10 y posterior. Para sistemas más antiguos, debe hacerlo manualmente. Al trabajar en nuevas versiones de iOS, puede establecer el número deseado de fotogramas por segundo. En la mayoría de los casos, 15 cuadros por segundo más o menos, para no desperdiciar potencia informática y no agregar trabajo innecesario a la aplicación.

Regla # 3
Cuando se trabaja con Objective-C, es útil usar el almacenamiento en caché de punteros IMP (punteros para la implementación de métodos). Cuando se llama al método
under the hood
en Objective-C, se
objc_msgSend()
función
objc_msgSend()
. Si el seguimiento muestra que la llamada tarda mucho tiempo, puede deshacerse de ella. De hecho, este es un repositorio de caché con punteros a una función, se les puede dar los nombres de algunos métodos. Por lo tanto, en lugar de realizar esta búsqueda cada vez, vale la pena hacer el almacenamiento en caché de la siguiente manera: coloque punteros de función en la memoria caché y llámelos directamente. Esto generalmente ocurre el doble de rápido.

Si no hay puntero, se llama al método utilizando el comando methodForSelector. Para llamar a este método de ayuda de la función de llamada habitual, debe ingresar el nombre del objeto en el selector, que produce los resultados de búsqueda. Quizás esta no sea la forma más conveniente, sino rápida.
Regla n. ° 4
No utilice ARC (conteo automático de referencias). ARC agrega mucho trabajo extra.
Cuando el ARC está habilitado, el compilador mismo dispersa la retain
/ release
en los lugares correctos. Sin embargo, si hay lugares donde retain
y release
toma demasiado tiempo, considere dejar caer el ARC. Haga esto si la optimización es necesaria, ya que tomará mucho tiempo.
A veces vale la pena abandonar incluso Swift, especialmente si el rendimiento de la aplicación es sensible a los cambios. Swift tiene algunas características realmente geniales, pero para realizar incluso tareas pequeñas, requiere escribir muchas líneas de código para lograr un alto nivel de funcionalidad.
Materiales utiles
La primera parte del artículo está disponible aquí . Para obtener más información sobre el tema, Luke Parham recomienda leer el libro " iOS y MacOS: Ajuste del rendimiento " y ver sus tutoriales .
La grabación de video del informe de Luke sobre MBLT DEV 2017 ahora es de dominio público:
Más conocimientos y consejos en MBLT DEV 2018
Los primeros oradores anunciaron:
- John C. Fox de Netflix hablará sobre localización de alta calidad, trabajando con condiciones de red agresivas y pruebas A / B.
- Krzysztof Zabłocki, The New York Times, está preparando un informe sobre patrones en iOS.
- Laura Morinigo, experta en desarrolladores de Google, habla sobre las mejores prácticas de Firebase.
Los últimos boletos anticipados volarán hoy.
