创建包装器与 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 反馈 — 无需本地设置。
此课程中的所有课时
- 创建包装器与 projectedValue
- 可复用性与约束
- 常见包装器模式(验证、缓存)