0Pricing
Swift Academy · Lezione

Pattern comuni per i wrapper (convalida, caching)

Crei wrapper comuni per la validation e il caching : verifichi l'input, fornisca valori predefiniti, memorizzi il risultato delle operazioni costose ed esponga flag di supporto tramite i valori proiettati.

Pattern comuni per i wrapper (convalida, caching) è una lezione Swift Academy gratuita su CoddyKit. Questa è la lezione 3 di 3. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Swift Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Swift Academy include 3 lezioni in totale.

Cosa costruiremo

Questa lezione mostra due modelli pratici:

  • Validazione: accettare o correggere gli input con valori predefiniti e messaggi.
  • Caching: memorizzare i risultati ed esporre tramite $helpers elementi come clear() e isCached.

Validazione: NonEmpty

@NonEmpty impedisce gli input vuoti e fornisce un valore predefinito. projectedValue segnala se l'ultimo valore impostato è stato corretto automaticamente.

@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)

Validazione basata su regole

@Validated è generico e accetta una closure di regola insieme a un valore di fallback. Lo utilizzi per controlli sulla lunghezza, sull'intervallo o personalizzati.

@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)  // false

Caching: memoizzazione lazy

@LazyCached memorizza in cache un valore ottenuto da una closure. $result espone gli helper isCached e 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)              // 1

Caching basato sul TTL

@TimedCache aggiorna il valore dopo un TTL. Il valore proiettato può esporre age, così il codice chiamante può decidere quando aggiornare il valore.

@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)

Linee guida di progettazione

Suggerimenti di progettazione:

  • Mantenga la validazione pura e prevedibile; segnali le correzioni con $flags.
  • Per il caching, mantenga ridotto lo stato e fornisca clear() o isCached.
  • Preferisca gli argomenti di init per le policy, come fallback e TTL.

Helper proiettati per il caching

Verifica rapida: che cosa dovrebbe esporre $value in un wrapper di caching?

Riepilogo

Riepilogo: utilizzi i wrapper per validare gli input, con valori predefiniti e regole, e per memorizzare in cache risultati costosi, con caricamento lazy o TTL. Inserisca il controllo e lo stato in projectedValue per mantenere pulito il codice chiamante.

Domande Frequenti

La lezione «Pattern comuni per i wrapper (convalida, caching)» è gratuita?

Sì — il testo completo di «Pattern comuni per i wrapper (convalida, caching)» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Swift Academy, passa a CoddyKit PRO. Il corso Swift Academy include 3 lezioni in totale.

Cosa imparerò in «Pattern comuni per i wrapper (convalida, caching)»?

Crei wrapper comuni per la validation e il caching : verifichi l'input, fornisca valori predefiniti, memorizzi il risultato delle operazioni costose ed esponga flag di supporto tramite i valori proie… Eserciti Swift Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Swift Academy?

Non è richiesta alcuna esperienza precedente. Swift Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 3.

Quanto tempo richiede la lezione «Pattern comuni per i wrapper (convalida, caching)»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Swift Academy?

Sì. Ogni lezione Swift Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Creare wrapper, projectedValue
  2. Riutilizzabilità e vincoli
  3. Pattern comuni per i wrapper (convalida, caching)
← Torna a Swift Academy