0Pricing
Swift Academy · Leçon

Modèles courants de wrappers (validation, mise en cache)

Créez des wrappers courants de validation et de mise en cache : contrôlez les données d’entrée, fournissez des valeurs par défaut, mémorisez les opérations coûteuses et exposez des indicateurs auxiliaires via les valeurs projetées.

Modèles courants de wrappers (validation, mise en cache) est une leçon Swift Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 3. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Swift Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Swift Academy comprend 3 leçons au total.

Ce que nous allons construire

Cette leçon présente deux modèles pratiques :

  • Validation : accepter ou corriger les entrées avec des valeurs par défaut et des messages.
  • Mise en cache : stocker les résultats et exposer des assistants comme $helpers, par exemple clear() et isCached.

Validation : NonEmpty

@NonEmpty bloque les entrées vides et fournit une valeur par défaut. La valeur projetée projectedValue indique si la dernière valeur définie a été corrigée automatiquement.

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

Validation : fondée sur une règle

@Validated est générique et accepte une fermeture rule ainsi qu’une valeur de fallback. Utilisez-le pour vérifier une longueur, une plage ou une condition personnalisée.

@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

Mise en cache : mémoïsation paresseuse

@LazyCached mémorise une valeur produite par une fermeture. $result expose les assistants isCached et 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

Mise en cache : basée sur TTL

@TimedCache actualise la valeur après un TTL. La valeur projetée peut exposer age afin que les points d’appel puissent décider du moment de l’actualisation.

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

Recommandations de conception

Conseils de conception :

  • Gardez la validation pure et prévisible ; signalez les corrections avec $flags.
  • Pour la mise en cache, limitez l’état au nécessaire ; fournissez clear() ou isCached.
  • Préférez les arguments d’initialisation pour les politiques (valeurs de repli, TTL).

Assistants projetés pour la mise en cache

Vérification rapide : que devrait exposer $value dans une enveloppe de mise en cache ?

Récapitulatif

Récapitulatif : utilisez les enveloppes pour valider les entrées (valeurs par défaut, règles) et pour mettre en cache les résultats coûteux (mémoïsation paresseuse, TTL). Placez le contrôle et l’état dans projectedValue pour obtenir des points d’appel clairs.

Questions Fréquemment Posées

La leçon « Modèles courants de wrappers (validation, mise en cache) » est-elle gratuite ?

Oui — le texte complet de « Modèles courants de wrappers (validation, mise en cache) » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Swift Academy, passe à CoddyKit PRO. Le cours Swift Academy comprend 3 leçons au total.

Qu'est-ce que j'apprendrai dans « Modèles courants de wrappers (validation, mise en cache) » ?

Créez des wrappers courants de validation et de mise en cache : contrôlez les données d’entrée, fournissez des valeurs par défaut, mémorisez les opérations coûteuses et exposez des indicateurs auxili… Tu pratiques Swift Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Swift Academy ?

Aucune expérience préalable n'est requise. Swift Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 3.

Combien de temps prend la leçon « Modèles courants de wrappers (validation, mise en cache) » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Swift Academy ?

Oui. Chaque leçon Swift Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Créer des wrappers, projectedValue
  2. Réutilisabilité et contraintes
  3. Modèles courants de wrappers (validation, mise en cache)
← Retour à Swift Academy