0

I have a class that implements an array of ObservableObjects that will save itself to persistent storage whenever one of the objects changes. Here is a very simplified version of the working code:

class MyObject : ObservableObject {
    @Published var name: String = ""
    // Lots of other @Published variables
}

class MyArray {
    @Published var objects: [MyObject] = []
    @Published private var objectWillChange: Void = ()

    private var objectChanged: AnyCancellable?

    init() {
        loadFromStorage()

        for object in objects {
            object.objectWillChange.assign(to: &$objectWillChange)
        }

        objectChanged = $objectWillChange.dropFirst().sink() {
            self.saveToStorage()
        }
    }

    func loadFromStorage() {
        // Loads objects from persistent storage
    }
    func saveToStorage() {
        // Saves objects to persistent storage
    }
}

This all works fine. Now I would like to create a generic version of this code, but I can't get it to compile.

Here is what I have so far

class MyPersistentArray: PersistentArray<MyObject> {
}

class PersistentArray<Object: ObservableObject> {
    @Published var objects: [Object] = []
    @Published private var objectWillChange: Void = ()

    private var objectChanged: AnyCancellable?

    init() {
        loadFromStorage()

        for object in objects {
            object.objectWillChange.assign(to: &$objectWillChange) // DOES NOT COMPILE
        }

        objectChanged = $objectWillChange.dropFirst().sink() {
            self.saveToStorage()
        }
    }

    func loadFromStorage() {
        // Loads objects from persistent storage
    }

    func saveToStorage() {
        // Saves objects to persistent storage
    }
}

In Xcode 14.2, the call to object.objectWillChange gives the following compiler error:

Cannot convert parent type 'Published<Void>' to expected type 'Published<Object.ObjectWillChangePublisher.Output>'

How can I fix this compiler error?

mstrsn
  • 21
  • 3

1 Answers1

0

I will answer my own question. I figured out that I had to constrain the ObservableObject using a where clause to limit the type of ObjetWillChangePublisher.Output to Void, like this:

protocol PersistentObject: ObservableObject where ObjectWillChangePublisher.Output == Void {
}

class MyObject : PersistentObject {
    @Published var name: String = ""
    // Lots of other @Published variables
}

class MyPersistentArray: PersistentArray<MyObject> {
}

class PersistentArray<Object: PersistentObject> {
    @Published var objects: [Object] = []
    @Published private var objectWillChange: Void = ()

    private var objectChanged: AnyCancellable?

    init() {
        loadFromStorage()

        for object in objects {
            object.objectWillChange.assign(to: &$objectWillChange)
        }

        objectChanged = $objectWillChange.dropFirst().sink() { _ in
            self.saveToStorage()
        }
    }

    func loadFromStorage() {
        // Loads objects from persistent storage
    }

    func saveToStorage() {
        // Saves objects to persistent storage
    }
}
mstrsn
  • 21
  • 3