Perfilado de código Swift: encontrando cuellos de botella de rendimiento

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: por qué perfilar código Swift es una necesidad



El desarrollo para iOS y macOS requiere alto rendimiento. Incluso un método lento puede causar lag en la UI, agotamiento de batería o congelamiento de la aplicación. Perfilar código Swift es el proceso de analizar el tiempo de ejecución, la memoria y el uso de CPU, que permite encontrar y eliminar cuellos de botella. Sin perfilamiento, la optimización se convierte en adivinanza: cambias el código al azar, sin saber qué es lo que realmente ralentiza.



En este artículo analizaremos las herramientas principales de perfilamiento de Swift: Xcode Instruments, os_signpost y la medición manual de tiempo. Aprenderás cómo encontrar funciones lentas, fugas de memoria y algoritmos ineficientes. El artículo será útil tanto para principiantes como para desarrolladores iOS experimentados.



Herramienta n.º 1: Xcode Instruments — tu asistente principal



Xcode Instruments es un potente conjunto de perfiladores integrado en Xcode. La herramienta más popular es Time Profiler. Muestra cuánto tiempo de CPU gasta cada función. Se inicia a través del menú Product > Profile o con la combinación Cmd + I.



Cómo usar Time Profiler



  1. Inicia el perfilamiento de tu aplicación.
  2. Realiza la acción que parece lenta (scroll, carga de datos, animación).
  3. Detén la grabación y observa la pila de llamadas.
  4. Encuentra las funciones con mayor tiempo de ejecución (columnas rojas).


Ejemplo: si tu tableView(_:cellForRowAt:) ocupa el 80% del tiempo, el problema está ahí. Un doble clic mostrará las líneas de código específicas.



Ejemplo de código para perfilamiento



Supongamos que tienes una función de carga de imágenes:



func loadImage(from url: URL) -> UIImage? {    guard let data = try? Data(contentsOf: url) else { return nil }    return UIImage(data: data)}


Time Profiler mostrará que Data(contentsOf:) bloquea el hilo principal. La solución es la carga asíncrona mediante URLSession.



Herramienta n.º 2: os_signpost — perfilamiento puntual



A veces es necesario medir solo una sección de código sin ensuciar el perfil general. Para esto usa os_signpost, una API ligera para marcar eventos. Los datos se incorporan automáticamente en Instruments.



Configuración de os_signpost



Primero importa os y crea un logger:



import os

let log = OSLog(subsystem: "com.yourapp.network", category: "Loading")


Luego envuelve el código a medir:



os_signpost(.begin, log: log, name: "FetchData")// Tu código de cargaos_signpost(.end, log: log, name: "FetchData")


En Instruments selecciona la plantilla os_signpost — verás el tiempo exacto de ejecución de cada bloque. Esto es indispensable al comparar dos algoritmos.



Ejemplo real: comparación de ordenamientos



Comparemos el ordenamiento estándar y el manual:



os_signpost(.begin, log: log, name: "SortBuiltin")let sortedBuiltin = largeArray.sorted()os_signpost(.end, log: log, name: "SortBuiltin")

os_signpost(.begin, log: log, name: "SortManual")let sortedManual = largeArray.sorted { $0 < $1 }os_signpost(.end, log: log, name: "SortManual")


El resultado a menudo sorprende: el ordenamiento integrado es 30-40% más rápido que el manual.



Herramienta n.º 3: Medición manual de tiempo con DispatchTime



Para comprobaciones rápidas sin Instruments usa DispatchTime. Es una forma sencilla de medir el tiempo de ejecución de una función directamente en el código.



Ejemplo de medición



let start = DispatchTime.now()// Bloque a medirlet result = heavyComputation()let end = DispatchTime.now()

let nanoTime = end.uptimeNanoseconds - start.uptimeNanosecondslet timeInterval = Double(nanoTime) / 1_000_000_000print("Tiempo de ejecución: \\(timeInterval) s")

Blogs

Book Recommendations