import Combine import Foundation func copyValues(at keyPaths: [PartialKeyPath], from source: T, to destination: inout T) { for keyPath in keyPaths.compactMap({ $0 as? any ValueCopyingKeyPath }) { keyPath.copyValue(from: source, to: &destination) } } extension _KeyValueCodingAndObservingPublishing where Self: NSObject { func publisher(forAll keyPaths: [PartialKeyPath], options: NSKeyValueObservingOptions = [.new]) -> AnyPublisher { let publishers = keyPaths.compactMap { ($0 as? any PublishableKeyPath)?.publisher(on: self, options: options) } return Publishers.MergeMany(publishers) .eraseToAnyPublisher() } } extension KeyPath: PublishableKeyPath where Root: NSObject { func publisher(on object: T, options: NSKeyValueObservingOptions) -> AnyPublisher? { precondition(object is Root) return unsafeDowncast(object, to: Root.self) .publisher(for: self, options: options) .map { _ in () } .eraseToAnyPublisher() } } extension WritableKeyPath: ValueCopyingKeyPath { func copyValue(from source: T, to destination: inout T) { precondition(source is Root) precondition(destination is Root) let keyPath = unsafeDowncast(self, to: WritableKeyPath.self) destination[keyPath: keyPath] = source[keyPath: keyPath] } } private protocol PublishableKeyPath { associatedtype Root func publisher(on object: T, options: NSKeyValueObservingOptions) -> AnyPublisher? } private protocol ValueCopyingKeyPath { associatedtype Root func copyValue(from source: T, to destination: inout T) }