Patrones comunes de wrappers (validación, caché)
Cree wrappers habituales de validation y caching : valide la entrada, proporcione valores predeterminados, memorice operaciones costosas y exponga indicadores auxiliares mediante valores proyectados.
Patrones comunes de wrappers (validación, caché) es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 3 de 3. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Swift Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Swift Academy incluye 3 lecciones en total.
Lo que construiremos
En esta lección se muestran dos patrones prácticos:
- Validación: acepte o corrija entradas con valores predeterminados y mensajes.
- Almacenamiento en caché: almacene resultados y exponga $helpers como
clear()yisCached.
Validación: NonEmpty
@NonEmpty protege frente a entradas vacías y proporciona un valor predeterminado. El projectedValue indica si el último valor asignado se corrigió automáticamente.
@propertyWrapper
struct NonEmpty {
private var value: String = ""
private(set) var lastFixed: Bool = false
var wrappedValue: String {
get { value }
set {
if newValue.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
value = "N/A" // default fallback
lastFixed = true
} else {
value = newValue
lastFixed = false
}
}
}
var projectedValue: Bool { lastFixed } // $name -> was fixed?
init(wrappedValue: String) { self.wrappedValue = wrappedValue }
}
struct Profile {
@NonEmpty var displayName: String = " "
}
var p = Profile()
print(p.displayName) // "N/A"
print(p.$displayName) // true (was fixed)Validación basada en reglas
@Validated es genérico y acepta un closure de regla además de un valor alternativo. Úselo para comprobaciones de longitud, rango o personalizadas.
@propertyWrapper
struct Validated<Value> {
private var value: Value
private let rule: (Value) -> Bool
private let fallback: Value
private(set) var lastValid: Bool = true
var wrappedValue: Value {
get { value }
set {
if rule(newValue) {
value = newValue
lastValid = true
} else {
value = fallback
lastValid = false
}
}
}
var projectedValue: Bool { lastValid } // $prop -> is valid?
init(wrappedValue: Value, rule: @escaping (Value) -> Bool, fallback: Value) {
self.rule = rule
self.fallback = fallback
self.value = wrappedValue
self.lastValid = rule(wrappedValue)
if !lastValid { self.value = fallback }
}
}
struct Form {
@Validated(rule: { $0.count >= 3 }, fallback: "???")
var nickname: String = "hi"
}
var f = Form()
print(f.nickname) // "???" (invalid -> fallback)
print(f.$nickname) // falseAlmacenamiento en caché: memoización diferida
@LazyCached memoiza un valor a partir de un closure. $result expone los helpers isCached y clear().
@propertyWrapper
struct LazyCached<Value> {
private var storage: Value?
private let build: () -> Value
var wrappedValue: Value {
mutating get {
if let v = storage { return v } // hit
let v = build() // miss -> compute
storage = v
return v
}
// Optional: allow manual set to override cache
set { storage = newValue }
}
struct Controls {
private let getter: () -> Bool
private let clearer: () -> Void
var isCached: Bool { getter() }
func clear() { clearer() }
}
var projectedValue: Controls {
Controls(
getter: { self.storage != nil },
clearer: { self.storage = nil }
)
}
init(_ build: @escaping () -> Value) {
self.build = build
self.storage = nil
}
}
// Demo: expensive computation (simulated)
var calls = 0
func heavy() -> Int { calls += 1; return (1...10_000).reduce(0, +) }
struct Engine {
@LazyCached(heavy) var result: Int
}
var e = Engine()
print(e.$result.isCached) // false
print(e.result) // computes once
print(e.result) // uses cache
print(calls) // 1Almacenamiento en caché basado en TTL
@TimedCache actualiza el valor después de un TTL. El valor proyectado puede exponer age para que los puntos de llamada decidan cuándo actualizarlo.
@propertyWrapper
struct TimedCache<Value> {
private var storage: Value?
private var timestamp: Date?
private let ttl: TimeInterval
private let build: () -> Value
var wrappedValue: Value {
mutating get {
let now = Date()
if let t = timestamp, let v = storage, now.timeIntervalSince(t) < ttl {
return v // fresh
}
let v = build() // refresh
storage = v
timestamp = now
return v
}
}
struct Status { let age: TimeInterval? }
var projectedValue: Status {
let age = timestamp.map { Date().timeIntervalSince($0) }
return Status(age: age)
}
init(ttl: TimeInterval, _ build: @escaping () -> Value) {
self.ttl = ttl
self.build = build
}
}
// Demo (age only; TTL behavior depends on real time)
struct Stats {
@TimedCache(ttl: 60) { Int.random(in: 0...1000) } var score: Int
}
var s2 = Stats()
print(s2.score) // computes
print(s2.$score.age ?? -1)Pautas de diseño
Consejos de diseño:
- Mantenga la validación pura y predecible; informe de las correcciones mediante $flags.
- Para el almacenamiento en caché, mantenga el estado reducido; proporcione clear() o isCached.
- Prefiera argumentos de inicialización para las políticas (valores alternativos, TTL).
Helpers proyectados para el almacenamiento en caché
Comprobación rápida: ¿Qué debería exponer $value en un wrapper de almacenamiento en caché?
Repaso
Repaso: Use wrappers para validar entradas (valores predeterminados, reglas) y para almacenar en caché resultados costosos (de forma diferida, con TTL). Incluya el control y el estado en projectedValue para mantener limpios los puntos de llamada.
Preguntas frecuentes
¿La lección «Patrones comunes de wrappers (validación, caché)» es gratis?
Sí — el texto completo de «Patrones comunes de wrappers (validación, caché)» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Swift Academy, actualiza a CoddyKit PRO. El curso de Swift Academy incluye 3 lecciones en total.
¿Qué aprenderé en «Patrones comunes de wrappers (validación, caché)»?
Cree wrappers habituales de validation y caching : valide la entrada, proporcione valores predeterminados, memorice operaciones costosas y exponga indicadores auxiliares mediante valores proyectados. Practicas Swift Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Swift Academy?
No se requiere experiencia previa. Swift Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 3.
¿Cuánto tiempo toma la lección «Patrones comunes de wrappers (validación, caché)»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Swift Academy?
Sí. Cada lección de Swift Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Crear wrappers, projectedValue
- Reutilización y restricciones
- Patrones comunes de wrappers (validación, caché)