Can you use @ObservableObject with protocol oriented programming?

I want to provide an object to a SwiftUI view.

POP would be a great way to define the interface for my object, while allowing me to provide a mock object for running in the simulator.
(I'm dealing with Bluetooth here - but this has more general application)

However - @ObservableObject doesn't seem compatible with protocol definition - it seems unable to detect that the protocol inherits from ObservableObject.

Is there a way to make this work?

all the options I'm trying here fail:

protocol Foo {}
protocol ObservableFoo: Foo,ObservableObject {}

struct TestView: View {
    @ObservedObject var foo:Foo
    @ObservedObject var anyFoo:any Foo
    @ObservedObject var observableFoo:ObservableFoo
    @ObservedObject var obsAndFoo:Foo & ObservableObject
    var body: some View {
        Text("Hello, World!")

Particularly frustrating is the error

Type 'any Foo & ObservableObject' (aka 'any ObservableObject & Foo') cannot conform to 'ObservableObject'

Don't think so. At the moment you'd have to use generics instead:

struct TestView<T: ObservableFoo>: View {
    @ObservedObject var foo: T


the limitation there is that I can only send in a concrete ObservableFoo rather than an existential any ObservableFoo

We have a custom property wrapper specifically for this, called @Store. Our implementation (Swift 5.5+) can be found here, which is in turn based on the (Swift 5.3-5.4) implementation from XUI here.

The idea is that XUI provides a version of ObservableObject with no associated types:

public protocol AnyObservableObject: AnyObject {
    var objectWillChange: ObservableObjectPublisher { get }

The default implementation of ObservableObject statisfies this protocol. To avoid warnings that any MyProtocol does not conform to AnyObservableObject, there is no constraint on the generic type, and instead it's conditionally downcasted:

if let observable = wrappedValue as? AnyObservableObject {
    // observable.objectWillChange is now a usable publisher
} else {
        "Only use the Store property wrapper with objects conforming to AnyObservableObject."

Once you have the usable objectWillChange in the first branch, you can observe that directly.

1 Like