SwiftUI:移除JSON数组重复项并在列表视图展示的问题
解决SwiftUI分类列表重复项问题
问题根源
你当前的代码无法去重的核心原因有两个:
CategoryViewModel使用let id = UUID()作为唯一标识,每个实例初始化时都会生成新的UUID——即使两个实例的category完全相同,它们也会被判定为不同的元素,导致去重逻辑失效。CategoryViewModel没有遵循Hashable协议,而你之前的去重扩展要求数组元素必须是Hashable类型,所以直接调用会报错。
解决方案
步骤1:修改CategoryViewModel,实现稳定标识与Hashable协议
让CategoryViewModel基于category内容来判断相等性,并遵循Hashable,这样去重逻辑才能正确识别重复的分类:
struct CategoryViewModel: Identifiable, Hashable { private var application: Application init(application: Application) { self.application = application } // 用category作为稳定的唯一标识,处理nil情况避免冲突 var id: String { category ?? "unknown-category-\(UUID().uuidString)" } var category: String? { application.category } // 基于category判断两个实例是否相等 static func == (lhs: CategoryViewModel, rhs: CategoryViewModel) -> Bool { lhs.category == rhs.category } // 基于category生成哈希值 func hash(into hasher: inout Hasher) { hasher.combine(category) } }
步骤2:在ViewModel层实现去重
你可以选择两种方式处理去重:
方式一:利用Set去重(自动去重后排序)
修改CategoryListViewModel的applications计算属性:
var applications: [CategoryViewModel] { // 将数组转为Set自动去重,再转回数组并按分类名称排序 Array(Set(appState.application)).sorted { ($0.category ?? "") < ($1.category ?? "") } }
方式二:使用你之前的removingDuplicates()扩展
现在CategoryViewModel已经是Hashable类型,直接调用扩展即可:
var applications: [CategoryViewModel] { appState.application.removingDuplicates().sorted { ($0.category ?? "") < ($1.category ?? "") } }
方式三:API数据获取后直接处理去重(更高效)
如果不需要保留同一分类下的多个应用实例,可以在获取API数据时直接分组去重,减少后续处理:
func getApps() async { do { let apiCall = try await Api().fetchApps() // 按category分组,取每组第一个实例(确保每个分类只保留一个) let uniqueCategoryApps = Dictionary(grouping: apiCall, by: { $0.category }) .values .compactMap { $0.first } .map(CategoryViewModel.init) appState.application = uniqueCategoryApps } catch { print(error) } }
额外注意事项
- 处理
category为nil的情况:可以将nil分类统一命名为"其他",避免生成大量带UUID的未知分类,提升用户体验。 - 排序:去重后建议对分类列表排序,保证界面展示的稳定性,避免每次刷新顺序变化。
内容的提问来源于stack exchange,提问作者VirtualCogs
相关产品推荐
相关产品推荐

