我有一份一直观察到的餐厅列表:

func getAllRestaurantsInParameters(lat: Double, long: Double){
        
        self.repo.getAllRestaurants().watch(block: {restaurants in
            
            self.restaurantList = (restaurants as! [Restaurant])
        })
}

在我的主视图中,我有一个NavigationView,其中包含NavigationLinks列表:

NavigationView{
            
     List{
         ForEach(restaurantList, id: \.self) { restaurant in
                             
                NavigationLink(destination: IndividualRestaurantView()){

                      ZStack {Text(restaurant.name)}
                }
         }
     } 
}

每当我进入任何Navigaiton Link餐厅并将其更改为另一家餐厅时,导航链接将自行返回到第一个主视图.为什么会发生这种情况?我假设这是因为观察者方法,每当发生变化时就会改变restaurantList,但我仍然不想回到主视图.

我该如何预防这种情况?

我确实测试了添加100 NavigationView上的.navigationViewStyle(.stack),但不起作用.

还有其他 Select 吗? .watch(块:将观察餐厅的任何变化并调用该方法.

如何防止导航链接本身返回导航视图?

推荐答案

您的假设是正确的,即自动导航回到主视图是由于getAllRestaurants()中的观察者触发了restaurantList的更改,这导致SwiftUI重新渲染视图并重置导航堆栈.以下是您问题的全面解决方案:

出现这个问题是因为每次更新您的restaurantList时,SwiftUI都会认为它需要更新整个视图,从而重置导航堆栈.为了解决这个问题,您可以通过手动管理导航链接的状态或改变处理数据更新的方式来使您的视图对数据更改更具弹性.以下是一些策略:

Option 1: Using a stable identifier for NavigationLink

如果餐厅符合Identiable,请使用其id而不是.\以获得更稳定的身份认同.如果Restaurant不符合Identiable,您可以向Restaurant模型添加标识符:

struct Restaurant: Identifiable {
    let id: UUID = UUID()
    var name: String
}

// Then in your view
ForEach(restaurantList, id: \.id) { restaurant in
    NavigationLink(destination: IndividualRestaurantView(restaurant: restaurant)){
        ZStack { Text(restaurant.name) }
    }
}

这样,即使restaurantList更新,SwiftUI也可以维护导航链接的状态,因为餐厅的身份没有更改.

Option 2: Avoid unnecessary updates

另一种方法是最大限度地减少对restaurantList本身的更新.仅在必要时更新restaurantList:

func getAllRestaurantsInParameters(lat: Double, long: Double){
    self.repo.getAllRestaurants().watch { restaurants in
        // Convert fetched array to identifiable if not already
        let updatedList = (restaurants as! [Restaurant])
        if updatedList.map(\.id) != self.restaurantList.map(\.id) {
            self.restaurantList = updatedList
        }
    }
}

此代码片段确保仅在获取的餐厅列表实际上与基于餐厅ID的当前列表不同时才更新restaurantList,从而可能减少不必要的视图刷新.

Option 3: Use a different state management approach

如果上述方法不能很好地适应您的应用程序的架构,请考虑对您的餐厅数据使用不同的状态管理方法,例如Observer:

class RestaurantViewModel: ObservableObject {
    @Published var restaurantList: [Restaurant] = []

    init() {
        loadRestaurants()
    }

    func loadRestaurants() {
        // Simulation of data fetch and watching
        repo.getAllRestaurants().watch { [weak self] restaurants in
            DispatchQueue.main.async {
                self?.restaurantList = (restaurants as! [Restaurant])
            }
        }
    }
}

// In your SwiftUI view
@StateObject private var viewModel = RestaurantViewModel()

NavigationView {
    List {
        ForEach(viewModel.restaurantList, id: \.id) { restaurant in
            NavigationLink(destination: IndividualRestaurantView(restaurant: restaurant)) {
                ZStack { Text(restaurant.name) }
            }
        }
    }
}

使用Observable对象并同步更新UI可以帮助更干净地管理状态更改并避免不必要的导航弹出.

通过使用这些策略之一,您应该能够控制SwiftUI应用程序中的数据更新引起的不必要的导航重置.由于我对您的应用程序的 struct 一无所知,请确保您 Select 正确的选项,因为这一切都是为了为您的特定应用程序的架构和需求找到正确的平衡.

希望这对你有帮助!

Swift相关问答推荐

将`@Environment`值赋给`Binding`参数

如何绑定环境变量ios17

使用View()和List()无法显示影子

如何隐藏集合视图中特定的单元格,以避免出现空白空间?

在 RealmSwift 中表示范围值?

Firebase removeObserver 在 Swift 5 中不起作用

如何在一个视图控制器中创建具有相同行为的多个集合视图?

SwiftUI:当 currentIndex 值更改时,数组中的第 n 个视图是否已换出?

与 SwiftUI 中的 onChange 修饰符相比,objectWillChangeSequence 的目的是什么?

将基于MyProtocol的泛型函数的参数更改为使用存在的any MyProtocol或some MyProtocol是否会受到惩罚?

试图同时实现两个混合过渡

如何在 RxSwift 中获取 controlEvent 类型?

如何删除标签和步进按钮之间的间距是 SwiftUI Stepper?

在 Swift 中计算两个日期之间的差异

iOS 判断应用程序是否可以访问麦克风

Xcode 7.3 Swift 的语法高亮和代码完成问题

在 iOS 中使用 Swift 保存 PDF 文件并显示它们

你如何在 UIBarItem 中使用 setTitleTextAttributes:forState?

判断用户是否登录到 iCloud?Swift /iOS

如何将应用程序与 iOS 联系人应用程序集成?