0
0
Swiftprogramming~15 mins

WrappedValue and projectedValue in Swift - Deep Dive

Choose your learning style9 modes available
Overview - WrappedValue and projectedValue
What is it?
In Swift, WrappedValue and projectedValue are parts of property wrappers, a feature that lets you add extra behavior to properties. WrappedValue is the actual value stored and accessed through the property. ProjectedValue is an optional extra value or functionality that the wrapper can provide, accessed with a special syntax. Together, they help manage how properties behave and interact in a clean, reusable way.
Why it matters
Without WrappedValue and projectedValue, adding extra behavior to properties would require repetitive code or complex patterns. They solve the problem of cleanly separating property logic from usage, making code easier to read, maintain, and reuse. This leads to safer and more expressive Swift programs, especially in UI frameworks like SwiftUI where state management is crucial.
Where it fits
Before learning this, you should understand basic Swift properties and functions. After this, you can explore SwiftUI state management, custom property wrappers, and advanced Swift features like Combine for reactive programming.
Mental Model
Core Idea
WrappedValue is the main property value you use, while projectedValue is an extra helper or feature the property wrapper offers alongside it.
Think of it like...
Imagine a gift box (property wrapper) that holds a present inside (wrappedValue). The box also has a tag or a card (projectedValue) that gives you extra information or instructions about the gift.
┌─────────────────────────────┐
│       Property Wrapper       │
│ ┌───────────────┐           │
│ │ wrappedValue  │ <--- main value
│ └───────────────┘           │
│ ┌───────────────┐           │
│ │ projectedValue│ <--- extra info or helper
│ └───────────────┘           │
└─────────────────────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding Property Wrappers Basics
🤔
Concept: Introduce what property wrappers are and how they wrap a property with extra behavior.
A property wrapper is a Swift feature that lets you define a reusable structure to add behavior to properties. You create a struct or class with a wrappedValue property. When you use @YourWrapper on a property, Swift uses wrappedValue to get and set the actual value.
Result
You can now create properties that automatically add behavior like validation or default values without repeating code.
Understanding property wrappers is key because wrappedValue is the core mechanism that connects your property to the wrapper's logic.
2
FoundationUsing wrappedValue in Practice
🤔
Concept: Learn how wrappedValue works as the main interface to the property value inside a wrapper.
Inside a property wrapper, wrappedValue is the property that stores or computes the actual value. When you access the property, Swift calls wrappedValue's getter or setter. For example: @propertyWrapper struct Capitalized { private var value: String = "" var wrappedValue: String { get { value } set { value = newValue.capitalized } } } @Capitalized var name: String name = "hello" print(name) // Prints "Hello"
Result
The property name automatically capitalizes any string assigned to it.
Knowing wrappedValue is how Swift connects your property to the wrapper's logic helps you design custom behaviors cleanly.
3
IntermediateIntroducing projectedValue for Extra Features
🤔Before reading on: do you think projectedValue is required for all property wrappers or optional? Commit to your answer.
Concept: Learn that projectedValue is an optional extra value or helper that a property wrapper can provide alongside wrappedValue.
Besides wrappedValue, a property wrapper can define a projectedValue property. This lets the wrapper expose extra functionality or data. You access it with the $ prefix on the property. For example: @propertyWrapper struct Logged { private var value: Int = 0 var wrappedValue: Int { get { value } set { print("Setting value to \(newValue)") value = newValue } } var projectedValue: String { "Current value is \(value)" } } @Logged var score: Int score = 10 print($score) // Prints "Current value is 10"
Result
You can access extra info or helpers about the property using $score, separate from the main value.
Understanding projectedValue unlocks how property wrappers can offer more than just a value, enabling richer APIs.
4
IntermediateAccessing projectedValue with $ Syntax
🤔Before reading on: do you think $property accesses the wrappedValue or projectedValue? Commit to your answer.
Concept: Learn the special $ syntax to access projectedValue from a property wrapper.
When you declare a property with a wrapper, Swift automatically creates a hidden property with a $ prefix. This property gives access to projectedValue. For example: @Logged var count: Int count = 5 print($count) // accesses projectedValue This syntax is consistent and lets you use the extra features the wrapper provides.
Result
You can easily get helper data or functions related to the property using $property syntax.
Knowing the $ syntax is essential to use projectedValue and take full advantage of property wrappers.
5
AdvancedCustomizing projectedValue Types and Uses
🤔Before reading on: can projectedValue be any type, or must it match wrappedValue's type? Commit to your answer.
Concept: Explore that projectedValue can be any type, not just related to wrappedValue, enabling flexible helper APIs.
ProjectedValue can be any type you want. It can be a simple value, a function, or even a complex object. For example, in SwiftUI, @State's projectedValue is a Binding, which lets you read and write the state indirectly. @propertyWrapper struct Toggleable { private var isOn: Bool = false var wrappedValue: Bool { get { isOn } set { isOn = newValue } } var projectedValue: () -> Void { { self.isOn.toggle() } } } @Toggleable var light: Bool light = true $light() // toggles light off
Result
You can create powerful helpers like toggle functions or bindings as projectedValue.
Understanding projectedValue's flexibility lets you design property wrappers that provide rich, expressive APIs beyond simple values.
6
AdvancedCombining wrappedValue and projectedValue in SwiftUI
🤔
Concept: See how SwiftUI uses wrappedValue and projectedValue to manage state and bindings in UI code.
In SwiftUI, @State is a property wrapper where wrappedValue is the current state value, and projectedValue is a Binding to that state. This lets views read the state directly and pass bindings to child views for two-way updates. @State var count: Int = 0 // count is wrappedValue // $count is Binding projectedValue This pattern makes UI code reactive and simple.
Result
SwiftUI views update automatically when state changes, thanks to wrappedValue and projectedValue working together.
Knowing how these two values work together explains why SwiftUI's state management is so elegant and powerful.
7
ExpertSurprising Behavior with ProjectedValue Initialization
🤔Before reading on: do you think projectedValue is always initialized automatically with wrappedValue? Commit to your answer.
Concept: Understand that projectedValue can be computed or stored separately, and its initialization can differ from wrappedValue, causing subtle bugs.
ProjectedValue is not automatically linked to wrappedValue unless you code it that way. You can store projectedValue independently or compute it on demand. For example, if projectedValue depends on external state or side effects, it might not reflect wrappedValue immediately. @propertyWrapper struct Counter { private var count = 0 var wrappedValue: Int { get { count } set { count = newValue } } var projectedValue: Int { count * 2 // computed separately } } @Counter var value: Int value = 3 print($value) // prints 6 But if you change count internally without updating projectedValue logic, they can get out of sync.
Result
You must carefully design projectedValue to stay consistent or document its behavior clearly.
Knowing projectedValue is independent helps prevent bugs where helpers don't match the main value, a common pitfall in complex wrappers.
Under the Hood
At runtime, Swift property wrappers are structs or classes with a wrappedValue property. When you declare @Wrapper var x, Swift generates code that accesses x.wrappedValue behind the scenes. The projectedValue is another property in the wrapper, accessed via the $ prefix. The compiler synthesizes storage and accessors to connect your property to these wrapper properties seamlessly.
Why designed this way?
Swift designed wrappedValue and projectedValue to separate the main property data from auxiliary features cleanly. This separation allows property wrappers to be flexible and reusable without cluttering the property's interface. The $ syntax provides a clear, concise way to access helpers without confusing the main value.
Property Wrapper Structure

┌───────────────────────────────┐
│ @Wrapper var property: Type   │
│                               │
│  ┌─────────────────────────┐  │
│  │ Wrapper Struct/Class     │  │
│  │ ┌───────────────┐       │  │
│  │ │ wrappedValue  │ <---- main property value
│  │ └───────────────┘       │  │
│  │ ┌───────────────┐       │  │
│  │ │ projectedValue│ <---- extra helper or info
│  │ └───────────────┘       │  │
│  └─────────────────────────┘  │
└───────────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does $property always return the same type as property? Commit to yes or no.
Common Belief:Many think $property returns the same type as the property itself.
Tap to reveal reality
Reality:$property returns the projectedValue, which can be any type, often different from the wrappedValue's type.
Why it matters:Assuming the same type can cause type errors or misuse of the projectedValue, leading to bugs or confusion.
Quick: Is projectedValue mandatory in every property wrapper? Commit to yes or no.
Common Belief:Some believe every property wrapper must have a projectedValue.
Tap to reveal reality
Reality:ProjectedValue is optional; wrappers can have only wrappedValue if no extra helper is needed.
Why it matters:Expecting projectedValue when none exists can cause compilation errors or wasted effort.
Quick: Does changing wrappedValue always update projectedValue automatically? Commit to yes or no.
Common Belief:People often think projectedValue automatically stays in sync with wrappedValue.
Tap to reveal reality
Reality:ProjectedValue can be independent or computed separately, so it may not reflect changes immediately or at all unless coded explicitly.
Why it matters:Misunderstanding this leads to inconsistent state and hard-to-find bugs in complex wrappers.
Quick: Can you use $property syntax on any property? Commit to yes or no.
Common Belief:Some think $property works on all properties, not just those with wrappers.
Tap to reveal reality
Reality:$property syntax only works on properties with wrappers that define projectedValue.
Why it matters:Trying to use $ on normal properties causes errors and confusion.
Expert Zone
1
ProjectedValue can be a function or closure, enabling property wrappers to expose actions, not just data.
2
The compiler synthesizes backing storage for wrappedValue but projectedValue storage is managed by the wrapper, allowing complex state management.
3
Stacking multiple property wrappers can combine their projectedValues in subtle ways, requiring careful design to avoid conflicts.
When NOT to use
Avoid property wrappers when you need dynamic behavior that depends heavily on runtime context or when the wrapper's overhead affects performance critically. Instead, use explicit methods or classes for complex state management.
Production Patterns
In production SwiftUI apps, @State and @Binding use wrappedValue and projectedValue to manage UI state and data flow. Custom wrappers often expose projectedValue as publishers or callbacks for reactive updates.
Connections
Encapsulation in Object-Oriented Programming
Property wrappers encapsulate property behavior, similar to how classes encapsulate data and methods.
Understanding encapsulation helps grasp why property wrappers separate wrappedValue and projectedValue to hide complexity and expose controlled interfaces.
Reactive Programming
ProjectedValue often exposes reactive bindings or publishers, linking property wrappers to reactive programming patterns.
Knowing reactive programming clarifies how projectedValue can provide streams or callbacks for changes, enabling responsive UI updates.
Metadata Tags in Data Annotation (e.g., in Databases)
ProjectedValue acts like metadata or annotations that provide extra info about data, similar to tags in databases.
Recognizing projectedValue as metadata helps understand its role in adding auxiliary data or behavior without changing the main value.
Common Pitfalls
#1Confusing wrappedValue and projectedValue types
Wrong approach:@propertyWrapper struct Example { var wrappedValue: Int var projectedValue: Int } @Example var number: Int let x: Int = $number // Error: $number is Int, but expected Int
Correct approach:@propertyWrapper struct Example { var wrappedValue: Int var projectedValue: String { "Value is \(wrappedValue)" } } @Example var number: Int let x: String = $number // Correct usage
Root cause:Assuming projectedValue must have the same type as wrappedValue causes type mismatches and misuse.
#2Using $property on a property without projectedValue
Wrong approach:@propertyWrapper struct Simple { var wrappedValue: Int } @Simple var count: Int print($count) // Error: No projectedValue defined
Correct approach:@propertyWrapper struct Simple { var wrappedValue: Int var projectedValue: Int { wrappedValue } } @Simple var count: Int print($count) // Works fine
Root cause:Forgetting to define projectedValue when intending to use $ syntax leads to compilation errors.
#3Assuming projectedValue updates automatically with wrappedValue
Wrong approach:@propertyWrapper struct Counter { var wrappedValue: Int var projectedValue: Int } @Counter var value: Int value = 5 print($value) // Might not reflect 5 if projectedValue not updated
Correct approach:@propertyWrapper struct Counter { var wrappedValue: Int { didSet { projectedValue = wrappedValue * 2 } } var projectedValue: Int init(wrappedValue: Int) { self.wrappedValue = wrappedValue self.projectedValue = wrappedValue * 2 } } @Counter var value: Int value = 5 print($value) // Correctly reflects 10
Root cause:Not linking projectedValue updates to wrappedValue changes causes inconsistent state.
Key Takeaways
WrappedValue is the main property value inside a Swift property wrapper, controlling how the property behaves.
ProjectedValue is an optional extra value or helper exposed by the wrapper, accessed with the $ prefix.
The $property syntax accesses projectedValue, enabling richer APIs like bindings or helper functions.
ProjectedValue can be any type and is independent from wrappedValue, so it requires careful design to stay consistent.
Understanding wrappedValue and projectedValue is essential for mastering Swift property wrappers and building clean, reusable code.