0

I’m using UIHostingController in order to present a SwiftUI flow (more or less 5 screens) inside a UIKit based app. But at the end of the SwiftUI flow, I need to return to the last ViewController presented. Does anyone know how to accomplish that behavior?

To put the problem in simple words:

Screen A (UIViewController) -> Screen B (SwiftUI view) -> Screen C (SwiftUI view) -> Screen D (SwiftUI view). Screen D needs to return to Screen A.

Notes:

  1. SwiftUI views use NavigationView and NavigationLink's.
  2. I looked at https://stackoverflow.com/a/61926030/6938899 but the answer solves the problem to return to Screen B (still a SwiftUI view).

EDIT

Added simplified version in code to explain the problem better:

import UIKit
import SwiftUI

// MARK: - Wrapper to use SwiftUI views inside UIKit
class SwiftUIWorkflowViewController: UIHostingController<SwiftUIWorkflowView> {
    
    override init(rootView: SwiftUIWorkflowView) {
        super.init(rootView: rootView)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
}

// MARK: - ViewModel for SwiftUI workflow
public final class SwiftUIWorkflowViewModel: ObservableObject { }

// MARK: - UIKit screen
class ScreenAViewController: UIViewController {
    
    //... other stuff
    
    private func navigateToSwiftUIFlow() {
        let swiftUIWorkflowViewModel = SwiftUIWorkflowViewModel()
        let deviceNetworkingVC = SwiftUIWorkflowViewController(
            rootView: SwiftUIWorkflowView(viewModel: swiftUIWorkflowViewModel)
        )

        navigationController?.pushViewController(deviceNetworkingVC, animated: true)
    }
}

// MARK: - Beggining of SwiftUI views
public struct SwiftUIWorkflowView: View {
    
    @Environment(\.presentationMode) private var presentationMode
    @ObservedObject var viewModel: SwiftUIWorkflowViewModel
    
    // MARK: - Init
    public init(viewModel: SwiftUIWorkflowViewModel) {
        self.viewModel = viewModel
    }
    
    // MARK: - Views
    public var body: some View {
        NavigationView {
            ScreenBView(onBack: { self.presentationMode.wrappedValue.dismiss() })
        }
        .environmentObject(self.viewModel)
    }
}

// MARK: - Screen B (SwiftUI)
public struct ScreenBView: View {
    
    @EnvironmentObject var viewModel: SwiftUIWorkflowViewModel
    
    var onBack: (() -> Void)? = nil
    
    public init(onBack: (() -> Void)? = nil) {
        self.onBack = onBack
    }
    
    public var body: some View {
        VStack {
            Text("Screen B")
            Button {
                self.onBack?()
            } label: {
                Text("Go back to UIKit screen")
            }
            NavigationLink(destination: ScreenBView()) {
                Text("Go to screen C")
            }
        }
    }
    
}

// MARK: - Screen C (SwiftUI)
public struct ScreenCView: View {
    
    @EnvironmentObject var viewModel: SwiftUIWorkflowViewModel
    
    public var body: some View {
        VStack {
            Text("Screen C - End of the SwiftUI flow!")
            // here I need a way to return to ScreenAViewController.
        }
    }
    
}
  • 1
    Can you construct a simple set that gets you to the point where you got stuck that we can try out? – jnpdx Sep 07 '21 at 17:46
  • @jnpdx, edited question with a simplified version of the real code. Thanks in advance! – Juan Manuel Gentili Sep 07 '21 at 18:07
  • 1
    So why can't you just tell the UIKit view controller to pop back to itself? I don't get why there's a difficulty. – matt Sep 07 '21 at 18:10
  • @matt, something like passing a closure that executes `navigationController?.popToRootViewController(animated: true)`? – Juan Manuel Gentili Sep 07 '21 at 18:22
  • 1
    If that's what you would do if SwiftUI weren't involved, sure. But the point is, all of UIKit is still available to you, so whatever you would do if SwiftUI weren't involved, just do that. – matt Sep 07 '21 at 18:37
  • Yes, you're right. It's solved with a closure and a `popToRootViewController`. Do you want to add an answer? I can check it as correct. – Juan Manuel Gentili Sep 07 '21 at 18:59

0 Answers0