import Foundation import Combine import SwiftUI /// View Model closable protocol - conform to this protocol if your view model should emit close block to close the screen that uses this view model public protocol ViewModelClosableProtocol { var closeCancellable: AnyCancellable? { get set } // when inheriting protocol, set @Published // var shouldCloseView: Bool { get set } // @Published ~== CurrentValueSubject, but we can't use property wrappers in protocol var shouldCloseView: CurrentValueSubject { get set } } extension ViewModelClosableProtocol { mutating func closeAction() { shouldCloseView.value = true } } public protocol ViewWithPresentationMode { var presentationMode: Binding { get } } public extension View where Self: ViewWithPresentationMode { @inlinable func onAppearSetupCloseCallback(closableViewModel: inout Closable) { closableViewModel.closeCancellable = closableViewModel.shouldCloseView.sink(receiveValue: { shouldClose -> Void in if shouldClose { presentationMode.wrappedValue.dismiss() } }) } } var SomeView: View, ViewWithPresentationMode { var body: some View { ZStack { }.onAppear { self.onAppearSetupCloseCallback(closableViewModel: &self.bussinessLogic.correctionDoseData) } } }