Creating wrappers, projectedValue
Build a custom wrapper, configure wrappedValue , and surface metadata/helpers with projectedValue ( $ ).
Why property wrappers?
A property wrapper is a reusable type that manages how a property is stored/read:
- wrappedValue: the public value
- projectedValue: extra API via
$ - Config via initializers/arguments
Clamped + projected flag
@Clamped limits a number to a range. The projectedValue ($hp) tells if the last set was 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)All lessons in this course
- Creating wrappers, projectedValue
- Reusability and constraints
- Common wrappers patterns (validation, caching)