As the name suggests its a wrapper over the property, so you can change the raw value before returning it. You can think of property wrapper as a regular property, which delegates its get and set to some other type. Property wrappers can be used with struct, enum and class.
Property wrappers are a feature that was introduced in Swift 5.1 and they play a huge role in SwiftUI and Combine which are two frameworks that shipped alongside Swift 5.1 in iOS 13.
The idea of property wrappers, is that commonly used computed property getter and setter patterns can be encapsulated into a type with a wrappedValue computed property:
@propertyWrapper
struct MyWrapper {
// ...
var wrappedValue : SomeType {
get { /*...*/ }
set { /*...*/ }
}
}
You can then declare your computed property using the property wrapper type name as a custom attribute:
@MyWrapper var myProperty
The result is that, behind the scenes, a MyWrapper instance is created for you, and when your code gets or sets the value of myProperty, it is the getter or setter of this MyWrapper instance that is called.
In real life, your property wrapper’s purpose will almost certainly be to act as a facade for access to a stored instance property, declared inside the property wrapper’s type.
To implement your own property wrapper, you need to do a few things:
struct that will wrap the property.@propertyWrapper before the struct keyword.var wrappedValue computed variable. You can use get to get the value of the property, and set to set it. With this, you can see that you can let a property wrapper store its value anywhere.To exemplify this, we will write a simple property wrapper that works with Strings and it changes them to uppercase letters.
@propertyWrapper
struct Capitalized {
private(set) var text: String = ""
var wrappedValue: String {
get { return text }
set { text = newValue.uppercased() }
}
}
struct User {
@Capitalized var firstName: String
@Capitalized var lastName: String
}
var user = User(firstName: "Thomas", lastName: "Anderson")
user.lastName // prints ANDERSON
Another example
@propertyWrapper
struct Rating {
private var _rating: Int = 0
var wrappedValue: Int {
get {
return _rating
} set (value) {
if value > 5 {
_rating = 5
} else if value < 1 {
_rating = 1
} else {
_rating = value
}
}
}
}
struct MusicRating {
@Rating var rating: Int
init(rating: Int) {
self.rating = rating
print(rating)
}
}
MusicRating(rating: 9)// prints 5
MusicRating(rating: 0)// prints 1
Styling UILabel
@propertyWrapper
public class TitleLabel {
public var wrappedValue: UILabel
public init(text: String) {
self.wrappedValue = UILabel()
wrappedValue.text = text
configureLabel()
}
private func configureLabel() {
wrappedValue.textColor = .lightGray
wrappedValue.font = .systemFont(ofSize: 28, weight: .regular)
wrappedValue.sizeToFit()
}
}
@TitleLabel(text: "The Matrix")
var titleLabel: UILabel
UserDefaults
UserPreferences is a property wrapper that helps to save and get values from UserDefaults.
@propertyWrapper
struct UserDefault<T> {
let key: String
let defaultValue: T
init(_ key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
var wrappedValue: T {
get {
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
}
struct UserData {
@UserDefault("hasVoted", defaultValue: false)
static var hasVoted: Bool
}
UserData.hasVoted = true
print(UserData.hasSeenAppIntroduction) // prints false
Also you can extend UserDefault and save custom object.