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