0Pricing
Swift Academy · 课时

创建包装器与 projectedValue

构建自定义包装器,配置 wrappedValue ,并通过 projectedValue ( $ )提供元数据和辅助功能。

创建包装器与 projectedValue 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 1 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 3 节课。

为什么使用属性包装器?

属性包装器是一种可复用的类型,用于管理属性的存储和读取方式:

  • wrappedValue:公共值
  • projectedValue:通过 $ 提供的额外接口
  • 通过初始化器或参数进行配置

Clamped 与投影标志

@Clamped 会将数字限制在一个范围内。projectedValue($hp)会告知上一次设置是否应用了 clamped 限制。

@propertyWrapper
struct Clamped {
    private var value: Int
    private let range: ClosedRange<Int>
    private(set) var wasClampedLastSet = false

    var wrappedValue: Int {
        get { value }
        set {
            let clamped = min(max(newValue, range.lowerBound), range.upperBound)
            wasClampedLastSet = (clamped != newValue)
            value = clamped
        }
    }

    var projectedValue: Bool { wasClampedLastSet } // $prop -> was it clamped?

    init(wrappedValue: Int, range: ClosedRange<Int>) {
        self.range = range
        let clamped = min(max(wrappedValue, range.lowerBound), range.upperBound)
        self.value = clamped
        self.wasClampedLastSet = (clamped != wrappedValue)
    }
}

struct Player {
    @Clamped(range: 0...100) var hp: Int = 120  // init clamps to 100
}

var p = Player()
print(p.hp)     // 100
p.hp = -5
print(p.hp, p.$hp)  // 0 true (was clamped)

规范化与备用视图

包装器可以转换输入(修剪/转为小写)。$property 可以公开一种实用的备用形式。

@propertyWrapper
struct Normalized {
    private var storage: String = ""
    var wrappedValue: String {
        get { storage }
        set { storage = newValue.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() }
    }
    var projectedValue: String { storage.uppercased() } // alternate view

    init(wrappedValue: String) { self.wrappedValue = wrappedValue }
}

struct User {
    @Normalized var username: String = "  Alice  "
}
let u = User()
print(u.username)   // "alice"
print(u.$username)  // "ALICE" (projected)

可配置包装器

向包装器传入参数(例如长度)。每次设置属性时,包装器都会应用格式化。

@propertyWrapper
struct Padded {
    private var value: String
    private let length: Int
    var wrappedValue: String {
        get { value }
        set {
            let s = newValue
            value = s.count >= length ? String(s.prefix(length))
                                      : s + String(repeating: " ", count: length - s.count)
        }
    }
    var projectedValue: Int { value.count } // current width
    init(wrappedValue: String, length: Int) {
        self.length = length
        self.value = ""
        self.wrappedValue = wrappedValue
    }
}

struct Row {
    @Padded(length: 6) var code: String = "AB"
}
var r = Row()
print("|\(r.code)|")   // |AB    |
print(r.$code)        // 6

通过 $value 实现 History

使用 projectedValue 公开更改历史等元数据,而不会使主要值接口变得杂乱。

@propertyWrapper
struct History<Value> {
    private var value: Value
    private(set) var changes: [Value] = []
    var wrappedValue: Value {
        get { value }
        set { changes.append(value); value = newValue }
    }
    var projectedValue: [Value] { changes } // $prop -> previous values
    init(wrappedValue: Value) { self.value = wrappedValue }
}

struct Settings {
    @History var level: Int = 1
}
var s = Settings()
s.level = 2
s.level = 3
print(s.level)    // 3
print(s.$level)   // [1, 2]

设计指导

提示:

  • 让包装器保持小型并专注于单一目标。
  • 记录 $projectedValue 会公开哪些内容。
  • 优先使用纯转换;避免产生大量副作用。
  • 提供清晰的初始化器和合理的默认值。

投影值的用途

快速检查:在包装器中,$property 用于什么?

回顾

回顾:使用 wrappedValue 实现 @propertyWrapper;通过 projectedValue($)公开辅助功能、标志或历史记录,并通过初始化器配置行为。

常见问题解答

「创建包装器与 projectedValue」课时是免费的吗?

是的 — 「创建包装器与 projectedValue」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 3 节课。

「创建包装器与 projectedValue」这节课中我会学到什么?

构建自定义包装器,配置 wrappedValue ,并通过 projectedValue ( $ )提供元数据和辅助功能。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 3 节。

「创建包装器与 projectedValue」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Swift Academy 课中编写并运行代码吗?

能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 创建包装器与 projectedValue
  2. 可复用性与约束
  3. 常见包装器模式(验证、缓存)
← 返回 Swift Academy