Composing property wrappers in Swift - Time & Space Complexity
When we combine property wrappers in Swift, it's important to see how the work done grows as we use more wrappers or properties.
We want to know how the time to access or set a property changes when wrappers are composed.
Analyze the time complexity of the following code snippet.
@propertyWrapper
struct WrapperA {
var wrappedValue: Int
}
@propertyWrapper
struct WrapperB {
var wrappedValue: Int
}
struct Example {
@WrapperA @WrapperB var number: Int
}
This code composes two property wrappers on one property, layering their behavior.
Look for repeated actions when accessing or setting the property.
- Primary operation: Accessing or setting the wrappedValue goes through each wrapper in order.
- How many times: Once per wrapper, so two times here.
As you add more wrappers, each access or set runs through all wrappers one by one.
| Number of Wrappers (n) | Approx. Operations |
|---|---|
| 1 | 1 |
| 5 | 5 |
| 10 | 10 |
Pattern observation: The work grows directly with the number of wrappers, one after another.
Time Complexity: O(n)
This means the time to get or set the property grows linearly with how many wrappers you compose.
[X] Wrong: "Composing multiple wrappers happens all at once, so time stays the same."
[OK] Correct: Each wrapper adds a step to access or set, so the time adds up, not stays flat.
Understanding how composing wrappers affects time helps you explain performance in real Swift code, showing you know how layering features impacts speed.
"What if each wrapper added extra work inside its getter or setter? How would that change the time complexity?"
Practice
Solution
Step 1: Understand property wrappers
Property wrappers add behavior to properties in Swift.Step 2: Define composition meaning
Composing means stacking multiple wrappers on one property to combine their effects.Final Answer:
Stack multiple property wrappers on a single property to combine behaviors -> Option DQuick Check:
Composing = stacking wrappers [OK]
- Thinking only one wrapper can be used per property
- Confusing subclassing with composing
- Applying wrappers to functions instead of properties
@WrapperA and @WrapperB on a property var value: Int such that @WrapperA is applied first (innermost)?Solution
Step 1: Recall property wrapper order
Property wrappers apply from right to left, so the rightmost is applied first.Step 2: Check syntax order
Correct syntax places wrappers before the property, so@WrapperB @WrapperA var value: Intapplies@WrapperAfirst, then@WrapperB.Final Answer:
@WrapperB @WrapperA var value: Int -> Option AQuick Check:
Right to left wrapper order = @WrapperB @WrapperA var value: Int [OK]
- Placing wrappers after the variable name
- Reversing the order of wrappers
- Using wrappers inside the variable declaration
@propertyWrapper
struct WrapperA {
var wrappedValue: Int
init(wrappedValue: Int) { self.wrappedValue = wrappedValue + 1 }
}
@propertyWrapper
struct WrapperB {
var wrappedValue: Int
init(wrappedValue: Int) { self.wrappedValue = wrappedValue * 2 }
}
struct Example {
@WrapperA @WrapperB var value: Int = 3
}What is the value of
Example().value?Solution
Step 1: Apply wrappers right to left
First,@WrapperBapplies: 3 * 2 = 6.Step 2: Apply
Then@WrapperAnext@WrapperAadds 1: 6 + 1 = 7.Final Answer:
7 -> Option AQuick Check:
(3 * 2) + 1 = 7 [OK]
- Applying wrappers left to right
- Forgetting to add 1 in WrapperA
- Multiplying after adding instead of before
@propertyWrapper
struct WrapperX {
var wrappedValue: Int
init(wrappedValue: Int) { self.wrappedValue = wrappedValue + 5 }
}
struct Test {
@WrapperX @WrapperX var number: Int = 10
}What is the error in this code?
Solution
Step 1: Check if multiple same wrappers allowed
Swift allows stacking the same property wrapper multiple times.Step 2: Analyze wrapper initialization
Each wrapper adds 5, so first adds 5 to 10 = 15, second adds 5 to 15 = 20.Final Answer:
No error; code compiles and runs correctly -> Option CQuick Check:
Same wrapper stacking allowed = No error; code compiles and runs correctly [OK]
- Assuming duplicate wrappers cause errors
- Expecting default initializer requirement
- Confusing runtime behavior with compile errors
@propertyWrapper
struct Clamped {
private var value: Int
let range: ClosedRange<Int>
var wrappedValue: Int {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
init(wrappedValue: Int, _ range: ClosedRange<Int>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
}
@propertyWrapper
struct Logged {
private var value: Int
var wrappedValue: Int {
get { value }
set {
print("Value changed to \(newValue)")
value = newValue
}
}
init(wrappedValue: Int) {
self.value = wrappedValue
}
}
struct Settings {
@Logged @Clamped(0...100) var score: Int = 150
}What will be printed and what is the final value of
Settings().score?Solution
Step 1: Apply wrappers right to left
First,@Clamped(0...100)clamps 150 to 100 in init.Step 2: Then
@Loggedreceives 100@Loggedinit sets value=100 directly (no setter called, no print).Final Answer:
Prints nothing, final value 100 -> Option BQuick Check:
Clamp then direct init set = no print, value 100 [OK]
- Thinking log prints during initialization
- Thinking clamp applies after log
- Assuming propagation calls inner setters
Ready to prove it?
Pass the test and this pattern moves unknown
