How to use property wrappers with @Observable Macro


Greetings, traveler!

Property wrapper is a cool Swift feature introduced in the 5.1 version. It helps to encapsulate some logic when dealing with properties. SwiftUI uses this feature a lot. Combine’s ObservableObject also relied on property wrappers. The number of property wrappers was reduced when the Observation framework was introduced. @Observable Macro turns all the properties published by default, even private ones, so there is no need to mark them with the @Published property wrapper.

But what would happen if we utilized our custom property wrapper with Observable class properties, for example, if we used a property wrapper-based DI approach?

@Observable
final class ViewModel {
    var data: [String] = []
    
    @Injected
    private var dataProvider: ProviderProtocol // ❌
    
    func loadData() {
        data = dataProvider.getData()
    }
}

We will receive this error.

❌ Property wrapper cannot be applied to a computed property

This will happen because the @Observable Macro turns the stored properties into computed ones under the cut. Since we can’t use property wrappers with computed properties, we will gain such a result.

Solution

There are two solutions. We can create a new Macro to use instead of your property wrapper. However, this may not always be suitable.

Another solution is to use Apple’s @ObservationIgnored Macro. While it is a bit weird-looking code, it will provide us with the desired result with less effort.

@Observable
final class ViewModel {
    var data: [String] = []
    
    @ObservationIgnored
    @Injected
    private var dataProvider: ProviderProtocol
    
    func loadData() {
        data = dataProvider.getData()
    }
}

Conclusion

The key difference between Swift property wrappers and Macros is that property wrappers are executed at runtime while Macros are evaluated at compile time. So, we can’t always count Swift Macros as the property wrapper’s alternative. While they can look similar in code, this is another tool with a different purpose. So, maybe we can expect something from Apple to make combining these tools more convenient.