よく使うラッパーのパターン(検証、キャッシュ)
一般的な 検証 ラッパーと キャッシュ ラッパーを構築します。入力をガードし、デフォルト値を提供し、コストの高い処理をメモ化して、projected valueでヘルパーフラグを公開します。
「よく使うラッパーのパターン(検証、キャッシュ)」はCoddyKit上の無料Swift Academyレッスンです。 これはレッスン3/3です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSwift Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Swift Academyコースには全3レッスンが含まれています。
作成するもの
このレッスンでは、次の2つの実用的なパターンを扱います。
- バリデーション: デフォルト値とメッセージを使って、入力を受け入れるか修正します。
- キャッシュ: 結果を保存し、$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)にはinitの引数を優先します。
キャッシュ用の射影ヘルパー
確認問題: キャッシュ用ラッパーの$valueには何を公開すべきでしょうか?
まとめ
まとめ: ラッパーを使って入力を検証し(デフォルト値、ルール)、コストの高い結果をキャッシュします(遅延、TTL)。制御や状態はprojectedValueにまとめ、呼び出し側をすっきりさせます。
よくある質問
「よく使うラッパーのパターン(検証、キャッシュ)」レッスンは無料ですか?
はい。「よく使うラッパーのパターン(検証、キャッシュ)」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Swift Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Swift Academyコースには全3レッスンが含まれています。
「よく使うラッパーのパターン(検証、キャッシュ)」で何を学びますか?
一般的な 検証 ラッパーと キャッシュ ラッパーを構築します。入力をガードし、デフォルト値を提供し、コストの高い処理をメモ化して、projected valueでヘルパーフラグを公開します。 ブラウザで直接実行するハンズオンコードでSwift Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Swift Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのSwift Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/3です。
「よく使うラッパーのパターン(検証、キャッシュ)」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このSwift Academyレッスンでコードを書いて実行できますか?
はい。すべてのSwift Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- ラッパーとprojectedValueの作成
- 再利用性と制約
- よく使うラッパーのパターン(検証、キャッシュ)