You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>类型的实例,输出的是结构体的原始调试信息,不会展示为用户可读的食物列表内容

修复方案
  1. 补全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)
    }
}
  1. 优化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() {
        // 本地持久化收藏数据的逻辑
    }
}
  1. 修正视图层代码错误,拼接收藏食物的名称为可读字符串后再传入文本组件,修正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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 07:36:18