从视图层次结构中移除SwiftUI NavigationView会导致EXC_BAD_ACCESS。

3

我在解决一个bug时遇到了些困难,不知道该如何解决或者去哪里寻找答案。

问题出现在我尝试将一个视图(它持有一个NavigationView)从视图层级中移除时。它崩溃并显示:Thread 1: EXC_BAD_ACCESS (code=1,address=0x10)

在尝试使用Sanitizer调试器之后,我得到了这个输出:*** -[_TtGC7SwiftUI41StyleContextSplitViewNavigationControllerVS_19SidebarStyleContext_ removeChildViewController:]: message sent to deallocated instance 0x10904c880

这表明这是由NavigationView引起的,但我仍然无法弄清楚如何解决此问题。

这个问题只会在真实设备上出现,在模拟器上可以正常工作,你可能需要多次登录、注销,再重新登录几次才会出现崩溃。

代码样例可参考:https://github.com/Surferdude667/NavigationRemoveTest

代码如下:

NavigationRemoveTestApp

@main
struct NavigationRemoveTestApp: App {
    var body: some Scene {
        WindowGroup {
            RootView()
        }
    }
}

RootView

struct RootView: View {

    @StateObject private var viewModel = RootViewModel()

    var body: some View {
        if !viewModel.loggedIn {
            WelcomeView()
        } else {
            ContentView()
        }
    }
}

RootViewModel

class RootViewModel: ObservableObject {

    @Published var loggedIn = false

    init() {
        LogInController.shared.loggedIn
            .receive(on: DispatchQueue.main)
            .assign(to: &$loggedIn)
    }
}

欢迎界面

struct WelcomeView: View {
    var body: some View {
        NavigationView {
            VStack {
                Text("Welcome")
                NavigationLink("Go to login") {
                    LogInView()
                }
            }
        }
    }
}

登录视图

struct LogInView: View {
    var body: some View {
        VStack {
            Text("Log in view")
            Button("Log in") {
                LogInController.shared.logIn()
            }
        }
    }
}

ContentView

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Content view")
            Button("Log out") {
                LogInController.shared.logOut()
            }
        }
    }
}

登陆控制器

import Combine
class LogInController {

    static let shared = LogInController()

    var loggedIn: CurrentValueSubject<Bool, Never>

    private init() {
        self.loggedIn = CurrentValueSubject<Bool, Never>(false)
    }

    func logIn() {
        self.loggedIn.send(true)
    }

    func logOut() {
        self.loggedIn.send(false)
    }
}

我也看到了相同的问题,请提交反馈! - damirstuhec
2个回答

4
我找到了几个解决方案。
  1. 将if语句包装在RootView中的NavigationView中,而不是将NavigationView放在实际视图中,可以解决问题。但这并不是很方便,因为现在所有内容都被包装在NavigationView中。

  2. 使用新的iOS 16 NavigationStack替换NavigationView也可以解决问题。


使用fullScreenCover来解决这个问题,我也遇到了同样的问题。 - LiangWang

0
哇,老兄,我也遇到了同样的问题,多亏了这篇帖子,问题解决了。但你觉得这是一个非常奇怪的 bug 吗?你有没有找出更深层次的原因?不管怎样,你让我的一天变得美好了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接