Fatal error: No ObservableObject of type DestinationBuilderHolder found when mixing UIKit and SwiftUI
Hey @johnpatrickmorgan. I'm having an issue running iOS 15, using the latest version (0.9) of the library, and mixing SwiftUI and UIKit. For reference, our app has some UIKit navigation (via a UINavigationController), and some SwiftUI navigation (via embedded views in UIViewControllers, and using the NavigationBackport library).
I kept getting the error described in the title and couldn't figure out what was wrong. I realized the issue occurs when I have the following structure:
UINavigationController ----UIViewController (root view controller) --------SwiftUIView using NavigationStack (embedded in above ViewController).
When using the popToRoot functionality, I get the error described above each time.
Here's some sample code you can use to reproduce the issue.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
embedView()
navigationController?.navigationBar.isHidden = true
// Do any additional setup after loading the view.
}
func embedView() {
let v = ContentView()
let hostingController = UIHostingController(rootView: v)
addChild(hostingController)
hostingController.view.backgroundColor = UIColor.white
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingController.view)
hostingController.didMove(toParent: self)
NSLayoutConstraint.activate([
hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
}
import SwiftUI
import NavigationBackport
struct ContentView: View {
@State var path: NBNavigationPath = NBNavigationPath()
@ViewBuilder private var SplashScreen: some View {
VStack {
Spacer()
Text("0")
Spacer()
Button {
path.push(Screen.first)
} label: {
Text("Next")
}
}
}
var body: some View {
NBNavigationStack(path: $path) {
SplashScreen
.nbNavigationDestination(for: Screen.self) { screen in
ViewForScreen(screen: screen)
}
}
}
}
struct ViewForScreen: View {
@EnvironmentObject var coordinator: PathNavigator
var screen: Screen
var buttonText: String {
if let nscreen = screen.nextScreen {
return "Next"
} else {
return "Pop to root"
}
}
func buttonAction(_ nextScreen: Screen? = nil) {
if let nextScreen {
coordinator.push(nextScreen)
} else {
coordinator.popToRoot()
}
}
var body: some View {
VStack {
Spacer()
Text(screen.number)
Spacer()
Button {
buttonAction(screen.nextScreen)
} label: {
Text(buttonText)
}
}
}
}
enum Screen: Hashable {
case first
case second
case third
case fourth
case fifth
var number: String {
switch self {
case .first:
return "1"
case .second:
return "2"
case .third:
return "3"
case .fourth:
return "4"
case .fifth:
return "5"
}
}
var nextScreen: Screen? {
switch self {
case .first:
return .second
case .second:
return .third
case .third:
return .fourth
case .fourth:
return .fifth
case .fifth:
return nil
}
}
}
If you embed the UIViewController in a UINavigationController, you'll be able to reproduce the issue. I've also attached a ZIP file here for your convenience.
I haven't been able to solve it yet by changing the configuration of the UINavigationController - not sure if there is anything you can change in the source code itself to fix this issue. Let me know if I can provide more info! Thanks
Thanks for raising this @ejubber, and for the reproduction. I was able to reproduce the issue, and as you pointed out, it only crashes when the whole thing is hosted in a UINavigationController, very strange! I have a few things I can try that might overcome the issue, will keep you posted.
Hello, I have the same problem, is there a fix ? Tanks for your help.
For information, problem could be reproductible in preview mode.
Hey @johnpatrickmorgan , I was able to reproduce this on iOS 16.1.1 as well - just a heads up
Find a solution?
It seems, issue is fixed in this commit f97c504
and now not able to reproduce this issue. if anyone still facing this, I can look into it.
Thanks @mwaqasbhati! That would suggest that the issue was caused by a difference in how the environment is propagated through the navigation stack between UIKit and SwiftUI. I'm glad that change seems to have fixed the issue!