NavigationSplitView - SwiftUI.AnyNavigationPath.Error.comparisonTypeMismatch

lac*_*her 8 ios swift swiftui

接收错误:

SwiftUI/NavigationColumnState.swift:520: Fatal error: 'try!' expression unexpectedly raised an error: SwiftUI.AnyNavigationPath.Error.comparisonTypeMismatch`
Run Code Online (Sandbox Code Playgroud)

当 NavigationSplitView 的详细信息视图发生更改,并且移动的详细信息视图具有NavigationStack(path: ...).

这看起来像是一个错误,尽管通常当我认为我做了一些愚蠢的事情时。如果有人能弄清楚的话,我很想知道解决方法或修复方法。

Xcode:版本 14.3 (14E222b) 模拟器: iPad Air(第 5 代)/My Mac(专为 iPad 设计)

楷模

SwiftUI/NavigationColumnState.swift:520: Fatal error: 'try!' expression unexpectedly raised an error: SwiftUI.AnyNavigationPath.Error.comparisonTypeMismatch`
Run Code Online (Sandbox Code Playgroud)

应用程序.swift

import SwiftUI 

final class AppModel: ObservableObject {
    @Published var appNavigation: AppNavigation? = .lists
    @Published var listsNavigation: [ListsNavigation] = []
    @Published var settingsNavigation: [SettingsNavigation] = []
}

enum AppNavigation {
    case lists, settings
}

enum SettingsNavigation {
    case settings1, settings2
}

enum ListsNavigation {
    case favourites, notes
}
Run Code Online (Sandbox Code Playgroud)

*列表视图

import SwiftUI

@main
struct splittyApp: App {
    @StateObject private var model = AppModel()

    var body: some Scene {
        WindowGroup {
            NavigationSplitView {
                List(selection: $model.appNavigation) {
                    NavigationLink(value: AppNavigation.lists) {
                        Label("Lists", systemImage: "list.clipboard")
                    }
                    
                    NavigationLink(value: AppNavigation.settings) {
                        Label("Settings", systemImage: "gearshape")
                    }
                }
            } detail: {
                switch model.appNavigation {
                case .lists: ListsView()
                case .settings: SettingsView()
                case .none: Text("Error")
                }
            }
            .environmentObject(model)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

设置视图

import SwiftUI

struct ListsView: View {
    @EnvironmentObject private var model: AppModel

    var body: some View {
        NavigationStack(path: $model.listsNavigation) {
            List {
                NavigationLink(value: ListsNavigation.favourites) {
                    Text("Favourites")
                }
                
                NavigationLink(value: ListsNavigation.notes) {
                    Text("Notes")
                }
            }
            .navigationDestination(for: ListsNavigation.self) { value in
                switch value {
                case .favourites: Text("Favourites View")
                case .notes: Text("Notes View")
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

示例项目: https://www.dropbox.com/s/jlxct4qeac8kt75/splitty.zip ?dl=0

重现步骤:

  • 在 iPad 上启动应用程序
  • 在主应用程序导航(列表/设置)之间点击

Chr*_*isR 3

发生该错误的原因是您在详细信息视图中使用了两种不同的导航枚举类型NavigationStack

即使您定义了两个NavigationStacks,每个详细信息子视图中一个,SwiftUI 也只创建一个。所以这两个代码的作用是相同的:

NavigationSplitView {
    ...
} detail: {
    View1()
    View2()
}


View1() ... {
    NavigationStack(path: $pathA) { ... }
}

View2() ... {
    NavigationStack(path: $pathA) { ... }
}
Run Code Online (Sandbox Code Playgroud)

等同于:

NavigationSplitView {
    ...
} detail: {
    NavigationStack(path: $pathA ? $pathB ?) { // which type?
        View1()
        View2()
    }
}

View1() ... {
}

View2() ... {
}
Run Code Online (Sandbox Code Playgroud)

第二个版本清楚地表明了 SwiftUI 为何举步维艰。它在路径中查找两种不同类型的值。

文档是这么说的,但是是以一种相当神秘的方式:

您还可以将 NavigationStack 嵌入到列中。...激活同一列中的链接会将视图添加到堆栈中。无论哪种方式,链接必须呈现一种数据类型,堆栈具有相应的 navigationDestination(for:destination:) 修饰符。

解决方案:

该问题的解决方案是对两个路径变量使用擦除的特殊类型NavigationPath。正是为了这个目的而引入的:

final class AppModel: ObservableObject {
    @Published var appNavigation: AppNavigation? = .lists
    @Published var listsNavigation = NavigationPath()
    @Published var settingsNavigation = NavigationPath()
}
Run Code Online (Sandbox Code Playgroud)