SwiftUI如何在不同视图间保留isFavorite状态,避免切换后重置为默认值
问题根因
- 全局
hasFavorites函数无法访问MainView中定义的@State countries变量,永远返回空数组,同时你的判断条件写的是count > 1,即使有1个收藏也会判定为无收藏,属于逻辑错误,这是你切换到收藏页看不到内容的直接原因。 - 你当前仅修改内存中的
countries数组,没有做持久化存储:Bundle中的JSON文件是只读的,APP重启/进程销毁后所有修改都会重置为默认值。
修复步骤
1. 修复收藏判断逻辑
删除全局的hasFavorites函数,在FavoritesView内部新增计算属性判断收藏列表,修正判断条件:
struct FavoritesView: View { @Binding var countries: [Country] // 内部计算收藏列表 private var favoriteCountries: [Country] { countries.filter { $0.isFavorite } } var body: some View { // 只要收藏数大于0就正常展示 if !favoriteCountries.isEmpty { Text("用户有收藏内容!") // 可在此处添加List展示所有收藏的国家 } else { Text("暂无收藏!") } } }
你还可以简化爱心图标切换的代码,无需写重复的if else:
Image(systemName: country.isFavorite ? "heart.fill" : "heart") .foregroundColor(.red) .onTapGesture { countries[index].isFavorite.toggle() // 后续加持久化存储调用 }
2. 添加数据持久化逻辑
由于Bundle中的资源文件不可修改,我们可以把修改后的国家列表存在UserDefaults(或者沙盒Documents目录),启动时优先读取本地存储的版本,不存在再读Bundle默认JSON。
首先新增存取工具方法(你的Country模型已经遵守Codable协议可直接用):
// 存储国家列表到本地 func saveCountries(_ countries: [Country]) { guard let encoded = try? JSONEncoder().encode(countries) else { return } UserDefaults.standard.set(encoded, forKey: "SavedCountries") } // 读取国家列表,优先读本地存储,无则读默认JSON func loadCountries() -> [Country] { guard let savedData = UserDefaults.standard.data(forKey: "SavedCountries"), let decoded = try? JSONDecoder().decode([Country].self, from: savedData) else { return Bundle.main.decode("Countries.json") } return decoded }
修改MainView的初始化逻辑,修改收藏状态后调用存储方法:
struct MainView: View { // 启动时优先读本地存储的数据 @State var countries: [Country] = loadCountries() var body: some View { TabView { ContentView(countries: $countries) .tabItem { Label("菜单", systemImage: "list.dash") } MapView() .tabItem { Label("地图", systemImage: "map") } FavoritesView(countries: $countries) .tabItem { Label("收藏", systemImage: "heart") } } } }
最后在爱心点击的toggle之后调用存储方法即可:
.onTapGesture { countries[index].isFavorite.toggle() saveCountries(countries) // 每次修改后持久化 }
修改完成后,切换Tab、杀APP重启都不会丢失收藏状态。
内容的提问来源于stack exchange,提问作者user17503091
相关产品推荐
相关产品推荐

