El ecosistema de desarrollo de Apple ha experimentado una transformación radical en los últimos años. Con la llegada de SwiftUI, la forma en que construimos interfaces de usuario pasó de ser imperativa (UIKit/AppKit) a declarativa. Sin embargo, ningún desarrollador es una isla, y tratar de reinventar la rueda para cada funcionalidad de tu aplicación es el camino más rápido hacia el agotamiento.
Aquí es donde entra el poder del Swift Package Manager (SPM) y la comunidad de código abierto.
En este artículo tutorial, exploraremos los 10 paquetes esenciales que todo desarrollador de SwiftUI debería tener en su arsenal. No solo los listaremos; analizaremos por qué son necesarios, cómo resuelven problemas específicos de SwiftUI y veremos ejemplos de código para que puedas integrarlos en tu proyecto de Xcode hoy mismo.
¿Por qué usar Paquetes de Terceros en SwiftUI?
Antes de sumergirnos en la lista, es vital entender la filosofía. Apple nos da herramientas increíbles (URLSession, CoreData, MapKit), pero a menudo estas API nativas requieren mucho código repetitivo (“boilerplate”) o carecen de funcionalidades específicas de UI que los usuarios modernos esperan.
Los paquetes seleccionados a continuación cumplen tres criterios:
- Swift-First: Escritos en Swift, aprovechando características modernas como Concurrencia (async/await) y Genéricos.
- Mantenimiento Activo: Bibliotecas vivas que se actualizan con cada versión de iOS.
- Compatibilidad con SwiftUI: No son simples wrappers de UIKit, sino que están diseñados para el ciclo de vida de las vistas de SwiftUI.
1. Kingfisher (Carga y Caché de Imágenes)
Aunque SwiftUI introdujo AsyncImage en iOS 15, sigue siendo básico. Carece de un sistema de caché avanzado en disco, transiciones complejas y manejo robusto de errores. Kingfisher es el estándar de oro para manejar imágenes desde la red.
¿Por qué usarlo?
Si tu app muestra un feed de noticias, perfiles de usuarios o una galería, necesitas caché. Sin él, tu app descargará la misma imagen una y otra vez, consumiendo los datos del usuario y ralentizando la UI.
Implementación
Kingfisher ofrece una vista KFImage que actúa como un sustituto directo de la vista Image nativa.
import SwiftUI
import Kingfisher
struct UserProfileView: View {
let imageURL: URL
var body: some View {
KFImage(imageURL)
.placeholder {
// Muestra esto mientras carga
ProgressView()
}
.onFailure { error in
print("Error de carga: \(error)")
}
.resizable()
.fade(duration: 0.25) // Transición suave
.aspectRatio(contentMode: .fill)
.frame(width: 150, height: 150)
.clipShape(Circle())
.cacheMemoryOnly() // Opcional: Configuración de caché
}
}2. The Composable Architecture (TCA)
A medida que tu aplicación crece, el manejo del estado (@State, @ObservedObject) puede volverse caótico. TCA, creado por Point-Free, es más que una librería; es un paradigma.
¿Por qué usarlo?
Proporciona una forma consistente de manejar el estado, la composición de funcionalidades, los efectos secundarios (como llamadas a API) y, lo más importante, hace que tu lógica sea 100% testeable.
Implementación Básica
TCA requiere cambiar tu mentalidad, pero el resultado es un código robusto.
import ComposableArchitecture
import SwiftUI
// 1. Definir el Estado y las Acciones
struct CounterFeature: Reducer {
struct State: Equatable {
var count = 0
}
enum Action {
case decrementButtonTapped
case incrementButtonTapped
}
// 2. Definir la lógica (Reducer)
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .decrementButtonTapped:
state.count -= 1
return .none
case .incrementButtonTapped:
state.count += 1
return .none
}
}
}
}
// 3. La Vista
struct CounterView: View {
let store: StoreOf<CounterFeature>
var body: some View {
WithViewStore(self.store, observe: { $0 }) { viewStore in
HStack {
Button("-") { viewStore.send(.decrementButtonTapped) }
Text("\(viewStore.count)")
Button("+") { viewStore.send(.incrementButtonTapped) }
}
}
}
}3. Lottie (Animaciones Vectoriales)
Las animaciones dan vida a una app, pero crear animaciones complejas en código es difícil. Lottie (de Airbnb) permite renderizar animaciones creadas en Adobe After Effects y exportadas como JSON.
¿Por qué usarlo?
Permite animaciones de alta calidad, escalables y pequeñas en tamaño de archivo. Es perfecto para pantallas de “Éxito”, loaders personalizados o tutoriales de onboarding.
Implementación
Usaremos la librería lottie-ios que ahora tiene soporte oficial para SwiftUI.
import SwiftUI
import Lottie
struct SuccessView: View {
var body: some View {
VStack {
LottieView(animation: .named("success_confetti"))
.playing(loopMode: .playOnce)
.resizable()
.frame(width: 200, height: 200)
Text("¡Operación completada!")
.font(.title)
}
}
}4. SwiftUI-Introspect
A veces, SwiftUI es demasiado abstracto. Puede que necesites acceder al UIScrollView subyacente de una List para quitar el rebote, o al UITextField para forzar el foco de una manera específica.
¿Por qué usarlo?
SwiftUI-Introspect te permite acceder a los componentes de UIKit (iOS) o AppKit (macOS) que están “debajo del capó” de las vistas de SwiftUI, sin romper la jerarquía declarativa.
Implementación
Un caso de uso común: deshabilitar el scroll en una lista específica.
import SwiftUI
import SwiftUIIntrospect
struct NoScrollListView: View {
var body: some View {
ScrollView {
Text("Contenido")
}
.introspect(.scrollView, on: .iOS(.v15, .v16, .v17)) { scrollView in
// Acceso directo al componente UIKit
scrollView.isScrollEnabled = false
scrollView.backgroundColor = .red
}
}
}5. Pulse (Logger de Red y Depuración)
Depurar llamadas de red URLSession puede ser frustrante si solo usas print(). Pulse es un logger de red potente que te permite ver las peticiones HTTP, cabeceras y respuestas JSON directamente en tu dispositivo iOS, sin necesidad de conectar el debugger de Xcode.
¿Por qué usarlo?
Es vital para equipos de QA y desarrolladores. Puedes agitar el dispositivo para ver el historial de red, compartir logs como archivos y ver imágenes decodificadas.
Implementación
La integración es sencilla si inyectas el URLSessionProxyDelegate.
import SwiftUI
import Pulse
import PulseUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onShake {
// Muestra la consola de Pulse al agitar
presentPulse()
}
}
}
}
// Vista para mostrar la consola (normalmente en una hoja debug)
struct DebugView: View {
var body: some View {
NavigationView {
ConsoleView()
}
}
}6. Exyte/PopupView
SwiftUI tiene .alert y .sheet, pero ¿qué pasa con los “Toasts” (mensajes flotantes) o popups personalizados que no bloquean toda la pantalla? PopupView de Exyte es la solución más elegante.
¿Por qué usarlo?
Permite crear notificaciones in-app no intrusivas (estilo Android Toast o notificaciones de iOS) con animaciones muy cuidadas.
Implementación
import SwiftUI
import PopupView
struct ContentView: View {
@State var showToast = false
var body: some View {
VStack {
Button("Mostrar Notificación") {
showToast = true
}
}
.popup(isPresented: $showToast) {
HStack {
Image(systemName: "checkmark.circle")
Text("Guardado correctamente")
}
.padding()
.background(Color.black.opacity(0.8))
.foregroundColor(.white)
.cornerRadius(12)
} customize: {
$0
.type(.floater(verticalPadding: 20))
.position(.top)
.animation(.spring())
.autohideIn(2)
}
}
}7. Factory (Inyección de Dependencias)
La Inyección de Dependencias (DI) es crucial para crear código desacoplado. Aunque SwiftUI tiene @EnvironmentObject, a veces es demasiado “mágico” o difícil de gestionar fuera de las Vistas. Factory es una librería moderna, segura en hilos y muy “Swifty”.
¿Por qué usarlo?
Reemplaza patrones antiguos como Swinject. Te permite definir tus servicios (API, Base de Datos) en un contenedor y recuperarlos fácilmente en tus ViewModels.
Implementación
import Factory
import SwiftUI
// 1. Definir el contenedor
extension Container {
var dataService: Factory<DataServiceProtocol> {
self { NetworkDataService() }.shared
}
}
// 2. Usarlo en un ViewModel
class ContentViewModel: ObservableObject {
// Inyección automática
@Injected(\.dataService) private var dataService
func loadData() {
dataService.fetch()
}
}8. MarkdownUI
Muchas aplicaciones necesitan renderizar texto rico que proviene de un backend (términos y condiciones, descripciones de productos, artículos de blog). SwiftUI tiene soporte básico para Markdown, pero MarkdownUI ofrece soporte completo, incluyendo tablas, bloques de código, citas y estilos personalizables.
¿Por qué usarlo?
Si tu CMS envía contenido en Markdown, renderizarlo nativamente en SwiftUI con estilos perfectos es difícil sin esta librería.
Implementación
import SwiftUI
import MarkdownUI
struct ArticleView: View {
let markdownContent = """
# Título Principal
Este es un texto en **negrita** y una lista:
- Elemento 1
- Elemento 2
```swift
print("Hola Mundo")
```
"""
var body: some View {
ScrollView {
Markdown(markdownContent)
.markdownTheme(.gitHub) // Estilo similar a GitHub
.padding()
}
}
}9. Swift Algorithms
Este paquete es mantenido por la propia Apple. Swift Algorithms incluye una suite de algoritmos de secuencia y colección que no están en la librería estándar.
¿Por qué usarlo?
A menudo escribimos lógica compleja en nuestros ViewModels para filtrar o agrupar datos para la UI. Este paquete simplifica esas tareas. Funciones como chunked, uniqued, windows o randomSample son salvavidas.
Implementación
Supongamos que quieres mostrar una lista de productos en una cuadrícula de 2 columnas, pero necesitas procesar los datos antes de dárselos a un LazyVGrid.
import Algorithms
let products = ["A", "B", "C", "D", "E"]
// Divide el array en trozos de 2
let chunks = products.chunks(ofCount: 2)
for chunk in chunks {
print(chunk) // ["A", "B"], ["C", "D"], ["E"]
}
// Eliminar duplicados basado en una propiedad
struct User { let id: Int; let name: String }
let users = [User(id: 1, name: "A"), User(id: 1, name: "B")]
let uniqueUsers = users.uniqued(on: \.id)10. RevenueCat (Compras In-App)
Implementar StoreKit nativamente es un dolor de cabeza: validación de recibos, manejo de suscripciones, periodos de prueba, errores de servidor. RevenueCat es el estándar de la industria para manejar IAP (In-App Purchases).
¿Por qué usarlo?
Ofrece un SDK que simplifica el proceso de compra a unas pocas líneas de código y un backend que gestiona la complejidad de la validación de recibos y el estado de la suscripción (Free vs Premium) entre plataformas (iOS y Android).
Implementación
import RevenueCat
import SwiftUI
class SubscriptionManager: ObservableObject {
@Published var isPremium = false
func purchase() {
Purchases.shared.getOfferings { (offerings, error) in
if let package = offerings?.current?.monthly {
Purchases.shared.purchase(package: package) { (transaction, info, error, userCancelled) in
if let info = info, info.entitlements["pro_access"]?.isActive == true {
self.isPremium = true
}
}
}
}
}
}Consejos Finales para la Gestión de Paquetes
¿SPM o CocoaPods?
La respuesta es rotunda: Usa Swift Package Manager (SPM). Está integrado en Xcode, es rápido y no requiere modificar tu proyecto con archivos .xcworkspace externos. CocoaPods es tecnología “legacy” para nuevos proyectos.
¿Cómo mantener el rendimiento?
Añadir paquetes aumenta el tiempo de compilación.
- Sé selectivo: No instales una librería entera para usar una sola función.
- Usa versiones exactas: En tu archivo de configuración de paquetes, trata de bloquear versiones mayores (ej. “Up to Next Major”) para evitar que una actualización rompa tu código, pero permitiendo parches de seguridad.
Conclusión
El desarrollo en SwiftUI se trata de composición. Al utilizar estos paquetes, no estás “haciendo trampa”, estás construyendo sobre los hombros de gigantes para entregar valor a tus usuarios más rápido.
Mi recomendación para tu próximo paso: Elige uno de estos paquetes que resuelva un problema actual en tu app e impleméntalo. Si estás luchando con imágenes, ve por Kingfisher. ¿El código es un lío? Prueba TCA o Factory.
Si tienes cualquier duda sobre este artículo, contacta conmigo y estaré encantado de ayudarte 🙂. Puedes contactar conmigo en mi perfil de X o en mi perfil de Instagram










