我使用UIKit和swiftUI构建了一个应用程序。
它在ios13.1中运行良好,但在ios13.2中我有错误:
我在UIViewController中显示SwiftUI视图(使用HostingController。此视图由NavigationLink中封装的元素组成。当点击这个元素时,下一个视图不会显示,尽管导航栏还可以,当点击返回时,应用程序崩溃:
<Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Tried to pop to a view controller that doesn't exist.'>
这是一个与ios 13.2有关的错误吗?知道怎么修吗?
这是我的代码:
UI控制器:
<类MyController:UIViewController{
var delegate: MenuItemsDelegate?
let vc = UIHostingController(rootView: MyView_UI())
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.0, *) {
view.backgroundColor = BACKGROUND_COLOR_D
} else {
view.backgroundColor = PALE_GREY
}
setupViews()
setNavigationBar()
}
func setupViews() {
addChild(vc)
view.addSubview(vc.view)
vc.didMove(toParent: self)
setupConstraints()
}
func setupConstraints() {
vc.view.translatesAutoresizingMaskIntoConstraints = false
[
vc.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
vc.view.centerXAnchor.constraint(equalTo: view.centerXAnchor),
vc.view.widthAnchor.constraint(equalTo: view.widthAnchor),
vc.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
].forEach {$0.isActive = true }
}
func setNavigationBar() {
title = ""
navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "slidingNotif").withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(handleMenuToggle))
setNavigationRightBarButtons()
}
@objc func handleMenuToggle() {
delegate?.handleMenuToggle(forMenuOption: nil)
}
}>
MyView_UI:<var body:some视图{
ScrollView{
VStack(spacing: 15) {
HStack(alignment: .center, spacing: 20) {
NavigationLink(destination: SecondView_UI(some param )){
ThirdView_UI(some param), height: 150)
}
NavigationLink(destination: SecondView_UI(some param)){
ThirdView_UI(some, height: 150)
}
}
.buttonStyle(PlainButtonStyle())
//autres HStack(...)
}
}
}
>
MyView_UI和SecondView_UI显示良好,但返回时应用程序崩溃
问题是UIKit和SwiftUI之间的桥接中的一个错误。它在某种程度上与此有关,但这里的原因是UIHostingController作为子级嵌入到另一个UIViewController中。不幸的是,如果您使用一些标准的容器视图控制器,如UIPageViewController,也会发生这种情况。
以下是坠机前的一些日志:
// we have ViewController0 in the navigation stack
// here we push ViewController1, that embeds UIHostingController, in our case - EmbeddedHostingController
pushViewController(_:animated:)
viewController: ViewController1
viewControllers: [ViewController0]
viewControllers: [ViewController0, ViewController1]
// here we tap a NavigationLink
// we can see that the pushed view controller is DestinationHostingController, coming from the framework
pushViewController(_:animated:)
viewController: DestinationHostingController<AnyView>
viewControllers: [ViewController0, ViewController1]
viewControllers: [ViewController0, ViewController1, DestinationHostingController<AnyView>]
// here we tap back in the navigation bar
// the DestinationHostingController is being popped, as expected
popViewController(animated:)
viewControllers:[ViewController0, ViewController1, DestinationHostingController<AnyView>]
super.result: DestinationHostingController<AnyView>
viewControllers: [ViewController0, ViewController1]
// this is the wrong part - the framework is triying to pop our embedded hosting controller, but because it is not part of the navigation stack - we get a crash
popToViewController(_:animated:)
viewController: EmbeddedHostingController
viewControllers: [ViewController0, ViewController1]
一个有效的解决方法是使用自定义UINavigationController子类,覆盖popToViewController
,并在viewController为UIHostingController类型时返回nil
。
有时还会发生另一种奇怪的崩溃——导航控制器试图弹出。
以下是一个示例解决方案:
private protocol HostingController {}
extension UIHostingController: HostingController {}
class RootNavigationController: UINavigationController {
override func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? {
if #unavailable(iOS 13.3) {
if #available(iOS 13.2, *) {
if viewController is HostingController, viewController.parent !== self {
return nil
}
if viewController === self {
return nil
}
}
}
return super.popToViewController(viewController, animated: animated)
}
}