Custom validation property wrappers help you check and control the values stored in properties easily and clearly.
Custom validation property wrappers in Swift
@propertyWrapper struct ValidationName { private var value: Type var wrappedValue: Type { get { value } set { // validation logic here if isValid(newValue) { value = newValue } else { // handle invalid value } } } init(wrappedValue initialValue: Type) { // validate initial value if isValid(initialValue) { self.value = initialValue } else { // handle invalid initial value self.value = defaultValue } } private func isValid(_ value: Type) -> Bool { // return true if value is valid return true } }
The @propertyWrapper keyword defines a wrapper around a property.
The wrappedValue is the actual property value with validation logic inside the setter.
@propertyWrapper struct NonEmpty { private var value: String = "" var wrappedValue: String { get { value } set { value = newValue.isEmpty ? "Default" : newValue } } init(wrappedValue: String) { self.wrappedValue = wrappedValue } }
@propertyWrapper struct Positive { private var value: Int = 1 var wrappedValue: Int { get { value } set { value = newValue > 0 ? newValue : 1 } } init(wrappedValue: Int) { self.wrappedValue = wrappedValue } }
This program uses a custom property wrapper @NonEmpty to make sure the user's name is never empty. If you try to set it empty, it changes to "Default" automatically.
import Foundation @propertyWrapper struct NonEmpty { private var value: String = "" var wrappedValue: String { get { value } set { value = newValue.isEmpty ? "Default" : newValue } } init(wrappedValue: String) { self.wrappedValue = wrappedValue } } struct User { @NonEmpty var name: String } var user = User(name: "") print("User name is: \(user.name)") user.name = "Alice" print("User name is: \(user.name)") user.name = "" print("User name is: \(user.name)")
Property wrappers can add validation without repeating code everywhere.
Use init(wrappedValue:) to validate the initial value when the property is created.
Remember to handle invalid values gracefully to avoid crashes.
Custom validation property wrappers help keep your data clean and safe.
They let you reuse validation rules easily across your code.
They make your code easier to read by separating validation from main logic.
Practice
Solution
Step 1: Understand property wrappers
Property wrappers in Swift add extra behavior to properties, such as validation.Step 2: Identify validation role
Custom validation wrappers check if values meet certain rules before storing them.Final Answer:
To automatically check and enforce rules on property values -> Option AQuick Check:
Validation = enforce rules [OK]
- Thinking wrappers change property type
- Confusing validation with access control
- Assuming wrappers store multiple values
NonEmpty for a String property in Swift?Solution
Step 1: Recall property wrapper syntax
In Swift, property wrappers are applied with @ before the wrapper name, placed before the variable declaration.Step 2: Match correct syntax
Correct syntax is@WrapperName var propertyName: Type, so@NonEmpty var name: Stringis correct.Final Answer:
@NonEmpty var name: String -> Option CQuick Check:
@WrapperName before var = correct syntax [OK]
- Placing @ after var
- Putting wrapper inside type
- Omitting @ symbol
Positive that only allows positive integers: @propertyWrapper
struct Positive {
private var value: Int = 1
var wrappedValue: Int {
get { value }
set { value = newValue > 0 ? newValue : 1 }
}
}
struct Account {
@Positive var balance: Int
}
let acc = Account()
print(acc.balance)
What will be printed when this code runs?Solution
Step 1: Understand default value in wrapper
The wrapper's private value starts at 1, and sets new values only if positive; else resets to 1.Step 2: Check initial property value
Account's balance uses @Positive but no initial value is set, so it uses wrapper's default 1.Final Answer:
1 -> Option AQuick Check:
Default wrapper value = 1 [OK]
- Expecting 0 as default
- Assuming nil is possible
- Thinking code won't compile
NonNegative but has an error: @propertyWrapper
struct NonNegative {
var value: Int
var wrappedValue: Int {
get { value }
set { if newValue >= 0 { value = newValue } }
}
}
struct Score {
@NonNegative var points: Int = -5
}
What is the main problem causing this code to fail?Solution
Step 1: Check property wrapper requirements
Property wrappers must have an init(wrappedValue:) to accept initial values.Step 2: Identify missing initializer
NonNegative lacks init(wrappedValue:) so compiler cannot assign -5 to points.Final Answer:
Property wrapper lacks an initializer to set initial value -> Option BQuick Check:
Missing init(wrappedValue:) = error [OK]
- Ignoring missing initializer
- Blaming setter logic
- Thinking default value assignment is invalid
LimitedLength that limits a String property's length to a maximum number of characters. Which of the following implementations correctly enforces this limit and allows setting the max length when declaring the property? @propertyWrapper
struct LimitedLength {
private var value: String = ""
private let maxLength: Int
var wrappedValue: String {
get { value }
set {
if newValue.count <= maxLength {
value = newValue
} else {
value = String(newValue.prefix(maxLength))
}
}
}
// Which initializer is correct?
???
}
struct User {
@LimitedLength(maxLength: 5) var username: String
}
Solution
Step 1: Understand property wrapper initialization with parameters
When a wrapper has parameters and initial value, it needs init(wrappedValue:maxLength:) to accept both.Step 2: Match initializer to usage
Usage passes maxLength: 5 and no initial value, so init(wrappedValue:maxLength:) fits best to set both.Final Answer:
init(wrappedValue: String, maxLength: Int) { self.maxLength = maxLength; self.value = wrappedValue } -> Option DQuick Check:
Use init(wrappedValue:maxLength:) for parameters [OK]
- Using init(maxLength:) only misses initial value
- Using init() without parameters
- Using init(wrappedValue:) without maxLength
Ready to prove it?
Pass the test and this pattern moves unknown
