如何在NavigationStack中传递Binding?解决Hashable协议兼容错误
错误根源
DataForSearch结构体中误用了@State属性包装器:@State仅能用于View类型的结构体,普通数据结构体不能使用该包装器。- 由于
@State是引用类型的包装器,Swift无法自动为包含它的结构体合成Hashable协议实现,这就是报错的直接原因。
正确修改方案
方案1:简化路径数据,直接传递Binding(推荐)
路径只传递searchTerm这类标识信息,目标视图的memes Binding直接从父视图的@State传递,无需将数据源放入路径中:
struct NavStack: View { @State private var memes = [MemeModel]() @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path){ VStack{ Text("Pass search result") .onTapGesture { // 路径仅传递搜索词 path.append("funny cats") } LazyVStack(spacing: 0){ ForEach(memes, id: \.memeid){ meme in Text(meme.title) } } } // 路径类型改为String .navigationDestination(for: String.self){ searchTerm in // 直接传递父视图的memes Binding SearchResults(searchTerm: searchTerm, memes: $memes) } .onAppear{ memes.append(MemeModel(memeid: 123, title: "meme1")) memes.append(MemeModel(memeid: 256, title: "meme2")) } } } } struct SearchResults: View { var searchTerm: String @Binding var memes: [MemeModel] var body: some View { VStack(spacing: 50){ Text(searchTerm) LazyVStack(spacing: 0){ ForEach(memes, id: \.memeid){ meme in Text(meme.title) } } } .onAppear{ memes.append(MemeModel(memeid: 345, title: "meme3")) memes.append(MemeModel(memeid: 678, title: "meme4")) } } } // 让MemeModel遵循Hashable(可选,但后续扩展场景更稳妥) struct MemeModel: Codable, Hashable { var memeid: Int var title: String }
方案2:修复DataForSearch的Hashable实现(不推荐)
如果一定要保留DataForSearch类型,需移除@State并确保关联类型遵循Hashable,让Swift自动合成协议实现:
// 移除@State,仅保留普通属性 struct DataForSearch: Hashable { var searchTerm: String var memes: [MemeModel] } // 让MemeModel遵循Hashable struct MemeModel: Codable, Hashable { var memeid: Int var title: String } struct NavStack: View { @State private var memes = [MemeModel]() @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path){ VStack{ Text("Pass search result") .onTapGesture { path.append(DataForSearch(searchTerm: "funny cats", memes: memes)) } LazyVStack(spacing: 0){ ForEach(memes, id: \.memeid){ meme in Text(meme.title) } } } .navigationDestination(for: DataForSearch.self){ selection in // 仍需传递父视图的$memes,路径中的memes是值拷贝,无法用作Binding SearchResults(searchTerm: selection.searchTerm, memes: $memes) } .onAppear{ memes.append(MemeModel(memeid: 123, title: "meme1")) memes.append(MemeModel(memeid: 256, title: "meme2")) } } } } // SearchResults结构体保持不变 struct SearchResults: View { var searchTerm: String @Binding var memes: [MemeModel] var body: some View { VStack(spacing: 50){ Text(searchTerm) LazyVStack(spacing: 0){ ForEach(memes, id: \.memeid){ meme in Text(meme.title) } } } .onAppear{ memes.append(MemeModel(memeid: 345, title: "meme3")) memes.append(MemeModel(memeid: 678, title: "meme4")) } } }
关键说明
- NavigationStack的
NavigationPath应存储值类型的标识数据,而非需要双向绑定的数据源,因为路径中的数据是值拷贝,无法直接作为Binding传递。 - 双向绑定的数据源需通过父视图的
@State配合$语法直接传递给子视图,这是SwiftUI中传递Binding的标准方式。
内容的提问来源于stack exchange,提问作者TheGreatCornholio
相关产品推荐
相关产品推荐

