Property Wrappers
A property wrapper is reusable magic you attach above a property to automatically add extra behavior every time it's read or written.
Syntax
@propertyWrapper
struct WrapperName {
var wrappedValue: Type {
get { /* return stored value */ }
set { /* validate, then store */ }
}
}
struct Model {
@WrapperName var property: Type
}
Defining a Simple Property Wrapper
A property wrapper struct implements wrappedValue, and any logic placed inside its getter and setter runs automatically whenever the wrapped property is accessed.
Example: Defining a Simple Property Wrapper
@propertyWrapper
// Define a struct `Clamped`
struct Clamped {
private var value: Int
private let range: ClosedRange<Int>
init(wrappedValue: Int, _ range: ClosedRange<Int>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
var wrappedValue: Int {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
}
// Define a struct `Settings`
struct Settings {
@Clamped(0...100) var volume: Int = 50
}
// Declare a mutable variable `settings`, initialized to `Settings()`
var settings = Settings()
settings.volume = 150
// Print `settings.volume` to the console
print(settings.volume)
Login to try C/C++/Java/PHP code in the editor
Using a Property Wrapper on Multiple Properties
Once defined, a property wrapper can be reused on any number of properties across different types, applying its behavior consistently everywhere.
Example: Using a Property Wrapper on Multiple Properties
@propertyWrapper
// Define a struct `Clamped`
struct Clamped {
private var value: Int
private let range: ClosedRange<Int>
init(wrappedValue: Int, _ range: ClosedRange<Int>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
var wrappedValue: Int {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
}
// Define a struct `GameCharacter`
struct GameCharacter {
@Clamped(0...100) var health: Int = 100
@Clamped(0...10) var level: Int = 1
}
// Declare a mutable variable `hero`, initialized to `GameCharacter()`
var hero = GameCharacter()
hero.health = -20
hero.level = 99
// Print "Health: \(hero.health), Level: \(hero.level)" to the console
print("Health: \(hero.health), Level: \(hero.level)")
Login to try C/C++/Java/PHP code in the editor
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the
view already swaps in the hi_ translation fields (or blanks these
out if untranslated), so this renders correctly for both languages
without a lang_code check here. #}
Common Mistakes
- Forgetting a property wrapper type must declare a
wrappedValueproperty; that's the required contract the@attribute relies on. - Confusing the wrapped value (accessed normally by name) with the wrapper instance itself (accessed with a leading
$, called the projected value). - Applying a property wrapper to a computed property; wrappers only apply to stored properties.
Chapter Summary
@propertyWrappermarks a struct or class as a reusable property wrapper.- The wrapper must expose a
wrappedValueproperty that Swift uses transparently. - Applying
@WrapperNameabove a property automatically routes access through the wrapper. - A
projectedValue(accessed with$name) can expose the wrapper itself for more advanced use.
🔒
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: