NavigationLink 在@ObservedObject 改变和使用@AppStorage 时跳回

NavigationLink jumps back when @ObservedObject is changed and @AppStorage is used

我在我的代码中找到了一个烦人的错误,并设法使用 xCode 的默认 iOS 应用程序作为起点并添加了一些代码来重现该问题。

问题

当满足以下条件时,修改@ObservedObject(核心数据实体)的一部分会导致视图立即跳回:

  1. 视图至少有 2 link 秒深度
  2. @AppStorage 在另一个视图中声明

我已经确认 (1) 如果我跳过 SubView2 并 link 直接进入 SubView3(编辑视图),那么该行为不会发生,并且 (2) 如果我注释掉 @AppStorage 中的行SettingsView() 则该行为不会发生。

在 SubView3 中,我点击“增加”以增加 item.value + 1。这导致视图跳回到 SubView2。

代码

我使用 CloudKit 和 SwiftUI 启动了一个默认 Xcode 项目,然后添加了一个 SettingsView(其中包含 @AppStorage)和两个子视图来查看特定项目。

import SwiftUI
import CoreData

struct SettingsView: View {
    
    @AppStorage("userSettingOne") var userSettingOne = false
    
    var body: some View {
        Text("Hello")
    }
}


struct SubView2: View {
    
    @ObservedObject var item2: Item
    
    @State private var showSubView3 = false
        
    var body: some View {
        
        NavigationLink(destination: SubView3(item3: item2) , isActive: $showSubView3) { EmptyView() }
                
        Text("Value: \(item2.value)")
        
        Button("SubView3", action: {
            showSubView3 = true
        })
            .navigationTitle("SubView2")
    }
}


struct SubView3: View {
        
    @ObservedObject var item3: Item

    var body: some View {
        
        VStack {
            Text("Value: \(item3.value)")
            Button("Increase", action: {
                item3.value += 1
            })
        }
            .navigationTitle("SubView3")
    }
}


struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
        animation: .default)
    private var items: FetchedResults<Item>
        
    var body: some View {
        NavigationView {
            List {
                ForEach(items) { item in
                    
                    NavigationLink("Item", destination: SubView2(item2: item))
                }
                .onDelete(perform: deleteItems)
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                ToolbarItem {
                    HStack {
                        Button(action: addItem) {
                            Label("Add Item", systemImage: "plus")
                        }
                        NavigationLink(destination: SettingsView(), label: {
                            Label("", systemImage: "gear").labelStyle(.iconOnly)
                        })
                    }

                }
            }
            Text("Select an item")
        }
    }
    
    // Boilerplate/default code below here

    private func addItem() {
        withAnimation {
            let newItem = Item(context: viewContext)
            newItem.timestamp = Date()
            do {
                try viewContext.save()
            } catch {
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            offsets.map { items[[=10=]] }.forEach(viewContext.delete)

            do {
                try viewContext.save()
            } catch {
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }
}

尝试将 .navigationViewStyle(.stack) 添加到您的 NavigationView