0Pricing
Swift Academy · Lekcja

Typowe wzorce wrapperów (walidacja, buforowanie)

Twórz typowe wrappery do walidacji i buforowania : sprawdzaj dane wejściowe, zapewniaj wartości domyślne, zapamiętuj wyniki kosztownych operacji i udostępniaj pomocnicze flagi przez wartości projektowane.

Typowe wzorce wrapperów (walidacja, buforowanie) to bezpłatna lekcja Swift Academy na CoddyKit. To lekcja 3 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Swift Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Swift Academy zawiera 3 lekcji w sumie.

Co zbudujemy

Ta lekcja przedstawia dwa praktyczne wzorce:

  • Walidacja: akceptowanie danych wejściowych lub ich poprawianie za pomocą wartości domyślnych i komunikatów.
  • Buforowanie: przechowywanie wyników i udostępnianie przez $helpers elementów takich jak clear() i isCached.

Walidacja: NonEmpty

@NonEmpty chroni przed pustymi danymi wejściowymi i dostarcza wartość domyślną. Właściwość projectedValue informuje, czy ostatnie przypisanie zostało automatycznie poprawione.

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

Walidacja oparta na regule

@Validated jest generyczna i przyjmuje closure rule oraz wartość fallback. Używaj jej do sprawdzania długości, zakresu lub własnych warunków.

@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

Buforowanie: leniwe memoizowanie

@LazyCached memoizuje wartość uzyskaną z closure. $result udostępnia elementy pomocnicze isCached i 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

Buforowanie oparte na TTL

@TimedCache odświeża wartość po upływie TTL. Wartość projectedValue może udostępniać age, dzięki czemu miejsce wywołania może zdecydować, kiedy wykonać odświeżenie.

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

Wskazówki projektowe

Wskazówki projektowe:

  • Zachowuj walidację jako czystą i przewidywalną; informuj o poprawkach za pomocą $flags.
  • W przypadku buforowania przechowuj niewielki stan; udostępniaj clear() lub isCached.
  • Preferuj argumenty inicjalizatora do przekazywania zasad działania, takich jak wartości zastępcze i TTL.

Pomocnicze elementy projectedValue do buforowania

Szybkie sprawdzenie: Co powinno udostępniać $value w wrapperze buforującym?

Podsumowanie

Podsumowanie: Używaj wrapperów do walidowania danych wejściowych, korzystając z wartości domyślnych i reguł, oraz do buforowania kosztownych wyników za pomocą leniwego obliczania i TTL. Umieszczaj elementy sterujące i informacje o stanie w projectedValue, aby miejsce wywołania pozostało przejrzyste.

Często zadawane pytania

Czy lekcja „Typowe wzorce wrapperów (walidacja, buforowanie)” jest bezpłatna?

Tak — pełny tekst „Typowe wzorce wrapperów (walidacja, buforowanie)” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Swift Academy, przejdź na CoddyKit PRO. Kurs Swift Academy zawiera 3 lekcji w sumie.

Co nauczysz się w „Typowe wzorce wrapperów (walidacja, buforowanie)”?

Twórz typowe wrappery do walidacji i buforowania : sprawdzaj dane wejściowe, zapewniaj wartości domyślne, zapamiętuj wyniki kosztownych operacji i udostępniaj pomocnicze flagi przez wartości projekto… Ćwiczysz Swift Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Swift Academy?

Nie wymagamy żadnego doświadczenia. Swift Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 3.

Ile czasu zajmuje lekcja „Typowe wzorce wrapperów (walidacja, buforowanie)”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Swift Academy?

Tak. Każda lekcja Swift Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Tworzenie wrapperów, projectedValue
  2. Możliwość ponownego użycia i ograniczenia
  3. Typowe wzorce wrapperów (walidacja, buforowanie)
← Powrót do Swift Academy