0Pricing
Swift Academy · Lesson

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

  1. Creating wrappers, projectedValue
  2. Reusability and constraints
  3. Common wrappers patterns (validation, caching)
← Back to Swift Academy