0Pricing
Swift Academy · Урок

Распространённые шаблоны обёрток (проверка, кэширование)

Создавайте распространённые обёртки для проверки и кэширования : проверяйте входные данные, задавайте значения по умолчанию, кэшируйте затратные операции и предоставляйте вспомогательные флаги через проецируемые значения.

«Распространённые шаблоны обёрток (проверка, кэширование)» — бесплатный урок Swift Academy на CoddyKit. Это урок 3 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 3 уроков всего.

Что мы создадим

В этом уроке рассматриваются два практических шаблона:

  • Проверка: принимать или исправлять входные данные с помощью значений по умолчанию и сообщений.
  • Кэширование: сохранять результаты и предоставлять $helpers, например clear() и isCached.

Проверка: NonEmpty

@NonEmpty не допускает пустые входные данные и подставляет значение по умолчанию. projectedValue сообщает, было ли последнее установленное значение исправлено автоматически.

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

Проверка по правилу

@Validated является обобщённой и принимает замыкание с правилом и запасным значением. Используйте её для проверки длины, диапазона или пользовательских условий.

@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

Кэширование: ленивая мемоизация

@LazyCached запоминает значение, полученное из замыкания. $result предоставляет вспомогательные возможности isCached и 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

Кэширование на основе TTL

@TimedCache обновляет значение после истечения TTL. Проецируемое значение может предоставлять age, чтобы вызывающий код мог решить, когда обновить значение.

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

Рекомендации по проектированию

Советы по проектированию:

  • Делайте проверку чистой и предсказуемой; сообщайте об исправлениях с помощью $flags.
  • При кэшировании храните минимум состояния; предоставляйте clear() или isCached.
  • Предпочитайте аргументы инициализации для политик, например запасных значений и TTL.

Проецируемые вспомогательные возможности для кэширования

Быстрая проверка: что должен предоставлять $value в обёртке для кэширования?

Итоги

Итоги: используйте обёртки для проверки входных данных, включая значения по умолчанию и правила, а также для кэширования затратных результатов с ленивой загрузкой и TTL. Помещайте управление и сведения о состоянии в projectedValue, чтобы вызывающий код оставался понятным.

Часто задаваемые вопросы

Урок «Распространённые шаблоны обёрток (проверка, кэширование)» бесплатный?

Да — полный текст урока «Распространённые шаблоны обёрток (проверка, кэширование)» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 3 уроков всего.

Чему я научусь в уроке «Распространённые шаблоны обёрток (проверка, кэширование)»?

Создавайте распространённые обёртки для проверки и кэширования : проверяйте входные данные, задавайте значения по умолчанию, кэшируйте затратные операции и предоставляйте вспомогательные флаги через… Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 3.

Сколько времени занимает урок «Распространённые шаблоны обёрток (проверка, кэширование)»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Создание обёрток, projectedValue
  2. Повторное использование и ограничения
  3. Распространённые шаблоны обёрток (проверка, кэширование)
← Назад к Swift Academy