Dynamically accessing `.objectWillChange`

Actually you can check PAT dynamically. See this thread.

import Combine

struct Dispatch<Model> {
    func apply<A, R0, R1>(_ a: A, _ f: (Model) -> R0) -> R1 {
        f(a as! Model) as! R1
    }
}

protocol ObservableObjectDispatch {
    func getObjectWillChange<T>(_ x: T) -> AnyPublisher<Void, Never>
}

extension Dispatch: ObservableObjectDispatch where Model: ObservableObject {
    func getObjectWillChange<T>(_ x: T) -> AnyPublisher<Void, Never> {
        apply(x) { $0.objectWillChange.eraseToAnyPublisher() }
    }
}

func getObjectWillChangeIfObservable<T>(_ x: T) -> AnyPublisher<Void, Never>? {
    (Dispatch<T>() as? ObservableObjectDispatch)?.getObjectWillChange(x)
}

// test
class MyObservable: ObservableObject {}

let x = MyObservable()
getObjectWillChangeIfObservable(x) // ok
getObjectWillChangeIfObservable("not observable") // nil

// for Any type, you also need _openExistential
let y: Any = MyObservable()
getObjectWillChangeIfObservable(y) // nil
_openExistential(y, do: getObjectWillChangeIfObservable) // ok
1 Like