Property wrappers are a powerful feature introduced in Swift 5.1 that allow you to add custom behavior to properties with minimal boilerplate code. They provide a way to encapsulate property storage and define reusable getter and setter logic.
Property wrappers are structs, enums, or classes that encapsulate read and write access to a property. They enable you to abstract away common property patterns, making your code more modular and easier to maintain.
To create a property wrapper, use the @propertyWrapper
attribute before the type definition:
@propertyWrapper
struct Capitalized {
private var value: String = ""
var wrappedValue: String {
get { value }
set { value = newValue.capitalized }
}
}
To use a property wrapper, simply add the wrapper's name with an @ symbol before the property declaration:
struct User {
@Capitalized var name: String
}
var user = User()
user.name = "john doe"
print(user.name) // Output: "John Doe"
Property wrappers can expose additional functionality through projected values, accessed using the $ prefix:
@propertyWrapper
struct Clamped<T: Comparable> {
private var value: T
private let range: ClosedRange<T>
var wrappedValue: T {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
var projectedValue: ClosedRange<T> { range }
init(wrappedValue: T, _ range: ClosedRange<T>) {
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
self.range = range
}
}
struct Temperature {
@Clamped(0...100) var celsius: Double
}
var temp = Temperature(celsius: 25)
print(temp.celsius) // Output: 25.0
print(temp.$celsius) // Output: 0.0...100.0
You can combine multiple property wrappers to create more complex behaviors:
@propertyWrapper
struct Trimmed {
private(set) var value: String = ""
var wrappedValue: String {
get { value }
set { value = newValue.trimmingCharacters(in: .whitespacesAndNewlines) }
}
init(wrappedValue: String) {
self.wrappedValue = wrappedValue
}
}
struct User {
@Trimmed @Capitalized var name: String
}
var user = User(name: " john doe ")
print(user.name) // Output: "John Doe"
To deepen your understanding of Swift property wrappers, explore these related topics:
By mastering property wrappers, you'll be able to write more concise, reusable, and maintainable Swift code. They are particularly useful when working with Swift Structures and Swift Classes, allowing you to add powerful behaviors to your properties with minimal effort.