📖 Scenario: You are building a simple user registration form in Swift. You want to make sure the user's input is valid before saving it.
🎯 Goal: Create a custom property wrapper to validate a username so it is at least 5 characters long. Use this property wrapper in a User struct and print the username if it is valid.
📋 What You'll Learn
Create a custom property wrapper called ValidatedUsername
The property wrapper should check that the username is at least 5 characters long
Create a User struct with a username property using the ValidatedUsername wrapper
Create an instance of User with the username "SwiftDev"
Print the username from the User instance
💡 Why This Matters
🌍 Real World
Property wrappers help keep your code clean by centralizing validation logic for user input or data models.
💼 Career
Understanding property wrappers and validation is useful for Swift developers building safe and maintainable apps.
Progress0 / 4 steps
1
Create the ValidatedUsername property wrapper
Create a property wrapper called ValidatedUsername with a wrappedValue property of type String. Initialize wrappedValue with an empty string.
Swift
Hint
Use @propertyWrapper before the struct. Define wrappedValue as a String property with default empty string.
2
Add validation logic to ValidatedUsername
Modify the ValidatedUsername property wrapper to accept an initial wrappedValue in its initializer. Add validation so that if the username is shorter than 5 characters, it sets wrappedValue to an empty string.
Swift
Hint
Use an initializer init(wrappedValue: String). Check the length with wrappedValue.count. Assign accordingly.
3
Create the User struct using ValidatedUsername
Create a struct called User with a property username that uses the @ValidatedUsername property wrapper.
Swift
Hint
Define struct User. Add @ValidatedUsername before var username: String.
4
Create a User instance and print the username
Create a constant user of type User with the username "SwiftDev". Then print user.username.
Swift
Hint
Create let user = User(username: "SwiftDev"). Then print(user.username).
Practice
(1/5)
1. What is the main purpose of a custom validation property wrapper in Swift?
easy
A. To automatically check and enforce rules on property values
B. To change the type of a property at runtime
C. To make properties private and inaccessible
D. To store multiple values in a single property
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 A
Quick Check:
Validation = enforce rules [OK]
Hint: Validation wrappers enforce rules on data automatically [OK]
Common Mistakes:
Thinking wrappers change property type
Confusing validation with access control
Assuming wrappers store multiple values
2. Which of the following is the correct syntax to declare a custom validation property wrapper named NonEmpty for a String property in Swift?
easy
A. var name: @NonEmpty String
B. var @NonEmpty name: String
C. @NonEmpty var name: String
D. NonEmpty var name: String
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: String is correct.
Final Answer:
@NonEmpty var name: String -> Option C
Quick Check:
@WrapperName before var = correct syntax [OK]
Hint: Use @ before wrapper name, then var property [OK]
Common Mistakes:
Placing @ after var
Putting wrapper inside type
Omitting @ symbol
3. Consider this Swift code using a custom validation property wrapper 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?
medium
A. 1
B. 0
C. nil
D. Compilation error
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 A
Quick Check:
Default wrapper value = 1 [OK]
Hint: Default wrapper value used if no initial value given [OK]
Common Mistakes:
Expecting 0 as default
Assuming nil is possible
Thinking code won't compile
4. This Swift code attempts to create a custom validation property wrapper 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?
medium
A. wrappedValue setter does not handle negative values correctly
B. Property wrapper lacks an initializer to set initial value
C. Cannot assign default value to property with wrapper
D. Missing @ symbol before property wrapper
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 B
Quick Check:
Missing init(wrappedValue:) = error [OK]
Hint: Add init(wrappedValue:) to accept initial values [OK]
Common Mistakes:
Ignoring missing initializer
Blaming setter logic
Thinking default value assignment is invalid
5. You want to create a custom validation property wrapper 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
}
hard
A. init(maxLength: Int) { self.maxLength = maxLength }