Introducción
El rendimiento de las aplicaciones móviles y de escritorio es un factor clave que influye en la experiencia del usuario. Los usuarios esperan que las aplicaciones se ejecuten de forma rápida, fluida y sin demoras. Para los desarrolladores de Swift que crean aplicaciones para el ecosistema Apple (iOS, macOS, watchOS, tvOS), la optimización del rendimiento se vuelve no solo deseable sino una tarea obligatoria. En este artículo, veremos los principales métodos para optimizar el rendimiento de las aplicaciones Swift, desde la gestión de memoria hasta el trabajo eficiente con múltiples hilos. Aprenderá cómo evitar errores comunes y hacer que su aplicación sea lo más rápida posible.
1. Gestión de Memoria y ARC
Swift utiliza el Conteo Automático de Referencias (ARC) para la gestión de memoria. Sin embargo, el uso incorrecto de ARC puede provocar fugas de memoria y una reducción del rendimiento. El problema principal son los ciclos de retención.
1.1. Evite los Ciclos de Retención
Los ciclos de retención ocurren cuando dos objetos se referencian entre sí, y ARC no puede desasignar su memoria. Use weak o unowned para romper el ciclo.
class Person { let name: String var apartment: Apartment? init(name: String) { self.name = name } deinit { print("\\(name) deallocated") }}
class Apartment { let unit: String weak var tenant: Person? // weak previene un ciclo de retención init(unit: String) { self.unit = unit } deinit { print("Apartment \\(unit) deallocated") }}
var john: Person? = Person(name: "John")var unit4A: Apartment? = Apartment(unit: "4A")john?.apartment = unit4Aunit4A?.tenant = johnjohn = nilunit4A = nil// Ambos objetos serán desasignados1.2. Use Tipos por Valor (Structs) en Lugar de Tipos por Referencia (Clases)
Las structs se almacenan en la pila, que es más rápida que el almacenamiento en el montón de las clases. Use structs para datos pequeños e inmutables.
struct Point { var x: Double var y: Double}
class PointClass { var x: Double var y: Double init(x: Double, y: Double) { self.x = x self.y = y }}
// Prueba de rendimientolet count = 1_000_000var start = CFAbsoluteTimeGetCurrent()var points = [Point](repeating: Point(x: 0, y: 0), count: count)for i in 0..<count { points[i].x = Double(i)}print("Structs: \\(CFAbsoluteTimeGetCurrent() - start) seconds")
start = CFAbsoluteTimeGetCurrent()var pointClasses = [PointClass]()for i in 0..<count { let p = PointClass(x: Double(i), y: 0) pointClasses.append(p)}print("Classes: \\(CFAbsoluteTimeGetCurrent() - start) seconds")2. Optimización del Trabajo con Múltiples Hilos (GCD)
Grand Central Dispatch (GCD) es una herramienta poderosa para ejecutar tareas en paralelo. Un uso inadecuado puede provocar bloqueos y una reducción del rendimiento.
2.1. Use las Colas Correctas
Para tareas en segundo plano, use colas globales con Calidad de Servicio (QoS):
.userInteractive— para tareas que requieren una respuesta inmediata (por ejemplo, animaciones)..userInitiated— para tareas iniciadas por el usuario (por ejemplo, carga de datos)..utility— para tareas de larga duración (por ejemplo, procesamiento de archivos)..background— para tareas que no afectan la interfaz de usuario (por ejemplo, sincronización).
DispatchQueue.global(qos: .userInitiated).async { // Tarea pesada let result = performHeavyCalculation() DispatchQueue.main.async { // Actualizar la UI en el hilo principal self.updateUI(with: result) }}2.2. Evite Bloquear el Hilo Principal
Todas las operaciones relacionadas con la interfaz de usuario deben realizarse en el hilo principal. Mueva los cálculos pesados y la red