SwiftUI如何正确展示Favorites类中Set<Food>集合的所有元素
问题说明
应用内置多张不同食物的展示图片,用户点击对应图片即可将该食物添加到Set<Food>类型的收藏集合中。需要在Favorites相关逻辑中展示集合内所有元素,使用Text("You like: \(favorites.comidas)")实现时无法正常运行,涉及代码如下:
初始Favorites类定义:
class Favorites: ObservableObject { var foods: Set<Food> }
完整Favorites类实现:
class Favorites: ObservableObject { var foods: Set<Food> init() { // load the saved data foods = [] } func contains(_ food: Food) -> Bool { foods.contains(food) } func add(_ food: Food) { objectWillChange.send() foods.insert(food) save() } func delete(_ food: Food) { objectWillChange.send() foods.remove(food) save() } }
Food模型定义:
struct Food: Identifiable, Hashable { var id: Int let name: String let foodImage: [String] // Equatable static func == (lhs: Food, rhs: Food) -> Bool { lhs.id == rhs.id } }
视图层实现:
@EnvironmentObject var favorites: Favorites let food: Food var body: Some View { Image(food.foodImage[0]) .onTapGesture { if favorites.contains(food) { favorites.delete(food) } else { favorites.add(food) } } }
问题原因
代码存在4个直接导致运行/显示异常的问题:
- 字符串插值中使用的属性名是
comidas,但Favorites类中定义的集合属性实际名为foods,属性名不匹配会直接触发编译错误 Food结构体声明遵循Hashable协议,但仅实现了Equatable要求的==方法,没有实现Hashable要求的哈希计算方法,会导致Set的插入、删除、判断包含等操作行为异常- 视图层
body的返回类型写为Some View,正确写法是首字母小写的some View,大小写错误会导致编译失败 - 即使属性名修正,直接在字符串中插值
Set<Food>类型的实例,输出的是结构体的原始调试信息,不会展示为用户可读的食物列表内容
修复方案
- 补全
Food模型的Hashable协议实现,哈希计算逻辑和相等判断逻辑保持一致,使用id生成哈希值:
struct Food: Identifiable, Hashable { var id: Int let name: String let foodImage: [String] // Equatable static func == (lhs: Food, rhs: Food) -> Bool { lhs.id == rhs.id } // 补全Hashable必要实现 func hash(into hasher: inout Hasher) { hasher.combine(id) } }
- 优化
Favorites类实现,使用@Published标记收藏集合属性,属性变更时会自动触发视图更新,无需手动调用objectWillChange.send(),同时补全缺失的save()方法逻辑:
class Favorites: ObservableObject { @Published var foods: Set<Food> init() { // 加载本地保存的收藏数据 foods = [] } func contains(_ food: Food) -> Bool { foods.contains(food) } func add(_ food: Food) { foods.insert(food) save() } func delete(_ food: Food) { foods.remove(food) save() } func save() { // 本地持久化收藏数据的逻辑 } }
- 修正视图层代码错误,拼接收藏食物的名称为可读字符串后再传入文本组件,修正
body类型的大小写错误:
struct FoodCell: View { @EnvironmentObject var favorites: Favorites let food: Food var body: some View { VStack { Image(food.foodImage[0]) .onTapGesture { if favorites.contains(food) { favorites.delete(food) } else { favorites.add(food) } } // 提取所有收藏食物的名称,拼接为可读字符串 let favoritedFoodNames = favorites.foods.map(\.name).joined(separator: "、") Text("你喜欢的食物: \(favoritedFoodNames)") } } }
内容的提问来源于stack exchange,提问作者Swifter64
相关产品推荐
相关产品推荐

