Rob*_*ert 34 uinavigationcontroller ios swift swiftui xcode11.2
最小的可重现示例(Xcode 11.2 beta,在Xcode 11.1中有效):
struct Parent: View {
    var body: some View {
        NavigationView {
            Text("Hello World")
                .navigationBarItems(
                    trailing: NavigationLink(destination: Child(), label: { Text("Next") })
                )
        }
    }
}
struct Child: View {
    @Environment(\.presentationMode) var presentation
    var body: some View {
        Text("Hello, World!")
            .navigationBarItems(
                leading: Button(
                    action: {
                        self.presentation.wrappedValue.dismiss()
                    },
                    label: { Text("Back") }
                )
            )
    }
}
struct ContentView: View {
    var body: some View {
        Parent()
    }
}
问题似乎在于将我放置NavigationLink在navigationBarItems嵌套于SwiftUI视图(其根视图为)的修改器内部NavigationView。崩溃报告表明,当我向前导航Child然后返回时,我试图弹出一个不存在的视图控制器Parent。
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Tried to pop to a view controller that doesn't exist.'
*** First throw call stack:
如果我将其放置NavigationLink在如下所示的视图主体中,则效果很好。
struct Parent: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: Child(), label: { Text("Next") })
        }
    }
}
这是SwiftUI错误还是预期行为?
编辑:我已经在Apple的反馈助手中给ID开了一个问题,FB7423964以防Apple有人担心:)。
编辑:我在反馈助手中打开票证表明有10多个类似的已报告问题。他们已使用更新了分辨率Resolution: Potential fix identified - For a future OS update。手指交叉,修复很快就到了。
Jus*_*gan 14
这对我来说是很痛苦的一点!我把它留了下来,直到我的大多数应用程序完成为止,并且我有足够的空间来处理崩溃问题。
我想我们都可以同意SwifUI有一些很棒的东西,但是调试可能很困难。
我认为这是一个错误。这是我的基本原理:
如果以大约半秒的异步延迟包装presentationMode dismiss调用,则应该发现该程序将不再崩溃。
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    self.presentationMode.wrappedValue.dismiss()
} 
这向我表明,该错误是SwiftUI如何与所有其他UIKit代码进行界面交互以管理各种视图的深处的意外行为。根据您的实际代码,您可能会发现,如果视图中存在一些较小的复杂性,则崩溃实际上不会发生。例如,如果您从一个视图中退出到一个具有列表的视图,并且该列表为空,则将在没有异步延迟的情况下崩溃。另一方面,如果在该列表视图中甚至只有一个条目,则强制循环迭代以生成父视图,您将看到崩溃不会发生。
我不太确定我将延迟中的dismiss调用包装起来的解决方案有多么健壮。我必须测试更多。如果您对此有任何想法,请告诉我!我很高兴向您学习!
这是一个主要的错误,我找不到解决它的正确方法。在iOS 13 / 13.1上工作正常,但13.2崩溃。
您实际上可以用一种更简单的方式来复制它(此代码实际上就是您所需要的)。
struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("Hello, World!").navigationBarTitle("To Do App")
                .navigationBarItems(leading: NavigationLink(destination: Text("Hi")) {
                    Text("Nav")
                    }
            )
        }
    }
}
希望苹果能解决这个问题,因为它肯定会破坏SwiftUI应用程序(包括我的)的负载。
This also has frustrated me for quite some time. Over the past few months, depending on the Xcode version, simulator version and real device type and/or version, it has gone from working to failing to working again, seemingly at random. However, recently it has been failing consistently for me, so yesterday I took a deep dive into it. I am currently using Xcode Version 11.2.1 (11B500).
看来问题围绕着导航栏和按钮的添加方式。因此,我没有使用按钮本身的NavigationLink(),而是尝试使用具有设置@State var的动作的标准Button()来激活隐藏的NavigationLink。这是罗伯特父视图的替代品:
struct Parent: View {
    @State private var showingChildView = false
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello World")
                NavigationLink(destination: Child(),
                               isActive: self.$showingChildView)
                { EmptyView() }
                    .frame(width: 0, height: 0)
                    .disabled(true)
                    .hidden()            
             }
             .navigationBarItems(
                 trailing: Button(action:{ self.showingChildView = true }) { Text("Next") }
             )
        }
    }
}
对我来说,这在所有模拟器和所有真实设备上都非常一致地工作。
这是我的助手视图:
struct HiddenNavigationLink<Destination : View>: View {
    public var destination:  Destination
    public var isActive: Binding<Bool>
    var body: some View {
        NavigationLink(destination: self.destination, isActive: self.isActive)
        { EmptyView() }
            .frame(width: 0, height: 0)
            .disabled(true)
            .hidden()
    }
}
struct ActivateButton<Label> : View where Label : View {
    public var activates: Binding<Bool>
    public var label: Label
    public init(activates: Binding<Bool>, @ViewBuilder label: () -> Label) {
        self.activates = activates
        self.label = label()
    }
    var body: some View {
        Button(action: { self.activates.wrappedValue = true }, label: { self.label } )
    }
}
这是用法示例:
struct ContentView: View {
    @State private var showingAddView: Bool = false
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello, World!")
                HiddenNavigationLink(destination: AddView(), isActive: self.$showingAddView)
            }
            .navigationBarItems(trailing:
                HStack {
                    ActivateButton(activates: self.$showingAddView) { Image(uiImage: UIImage(systemName: "plus")!) }
                    EditButton()
            } )
        }
    }
}
作为一种解决方法,根据上面 Chuck H 的回答,我将 NavigationLink 封装为一个隐藏元素:
struct HiddenNavigationLink<Content: View>: View {
var destination: Content
@Binding var activateLink: Bool
var body: some View {
    NavigationLink(destination: destination, isActive: self.$activateLink) {
        EmptyView()
    }
    .frame(width: 0, height: 0)
    .disabled(true)
    .hidden()
}
}
然后您可以在 NavigationView 中使用它(这很重要)并从导航栏中的 Button 触发它:
VStack {
    HiddenNavigationList(destination: SearchView(), activateLink: self.$searchActivated)
    ...
}
.navigationBarItems(trailing: 
    Button("Search") { self.searchActivated = true }
)
将其包装在“//HACK”注释中,以便在 Apple 修复此问题时您可以替换它。
| 归档时间: | 
 | 
| 查看次数: | 1814 次 | 
| 最近记录: |