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

SwiftUI:如何编写Fetch Request获取每日最大重量数据?

解决方案:按日期获取每日最大重量记录

要实现按日期取每日最大重量的需求,你有两种可行方案,根据数据量和性能需求选择即可:


方案一:内存中分组过滤(简单易实现,适合数据量不大的场景)

直接利用现有@FetchRequest获取所有相关记录,然后在内存中按日期分组,每组筛选出重量最大的那条记录,最后按日期排序用于图表绘制。

修改代码步骤:

  1. 在ExerciseDetailView中添加一个计算属性,处理原始数据:
// 处理后的数据:每个日期仅保留最大重量的记录
var dailyMaxSets: [ExerciseSet] {
    // 按当日起始时间分组
    let groupedByDate = Dictionary(grouping: exercisesets) { set in
        set.dateCompleted.startOfDay
    }
    // 每组取重量最大的记录,再按日期升序排序
    return groupedByDate.values.compactMap { setsInDay in
        setsInDay.max(by: { $0.weight < $1.weight })
    }.sorted { $0.dateCompleted < $1.dateCompleted }
}
  1. 修改图表数据源,同时修正Y轴绑定的属性(你原代码中写的是reps,需求是展示重量,所以改成weight):
Chart(dailyMaxSets) { e in
    LineMark(x: .value("日期", e.dateCompleted.startOfDay),
             y: .value("最大重量", e.weight)
    )
}
  1. 确保你的Date扩展包含startOfDay方法(如果没有的话添加):
extension Date {
    var startOfDay: Date {
        Calendar.current.startOfDay(for: self)
    }
}

方案二:Core Data聚合查询(性能更优,适合数据量大的场景)

如果你的运动记录数据量很大,内存处理会有性能损耗,可以直接通过Core Data的分组聚合查询,只获取每个日期的最大重量数据,减少数据传输量。

修改代码步骤:

  1. 创建一个简单模型存储聚合结果:
struct DailyMaxWeight: Identifiable {
    let id: Date
    let date: Date
    let maxWeight: Double
}
  1. 实现数据管理类,用于执行聚合查询:
class ExerciseDataManager: ObservableObject {
    @Published var dailyMaxWeights: [DailyMaxWeight] = []
    let exerciseName: String
    
    init(exerciseName: String) {
        self.exerciseName = exerciseName
        fetchDailyMaxWeights()
    }
    
    private func fetchDailyMaxWeights() {
        let request = NSFetchRequest<NSDictionary>(entityName: "ExerciseSet")
        // 过滤指定运动的记录
        request.predicate = NSPredicate(format: "exercisename == %@", exerciseName)
        // 按日期升序排序
        request.sortDescriptors = [NSSortDescriptor(key: "dateCompleted", ascending: true)]
        // 按当日起始时间分组
        request.propertiesToGroupBy = ["dateCompleted.startOfDay"]
        
        // 定义聚合表达式:获取每组的最大重量
        let maxWeightExpression = NSExpressionDescription()
        maxWeightExpression.name = "maxWeight"
        maxWeightExpression.expression = NSExpression(forFunction: "max:", arguments: [NSExpression(forKeyPath: "weight")])
        maxWeightExpression.expressionResultType = .doubleAttributeType
        
        // 指定要获取的字段
        request.propertiesToFetch = ["dateCompleted.startOfDay", maxWeightExpression]
        // 设置结果类型为字典
        request.resultType = .dictionaryResultType
        
        do {
            // 替换成你项目中实际的Core Data上下文
            let results = try PersistenceController.shared.container.viewContext.fetch(request)
            dailyMaxWeights = results.compactMap { dict in
                guard let date = dict["dateCompleted.startOfDay"] as? Date,
                      let maxWeight = dict["maxWeight"] as? Double else {
                    return nil
                }
                return DailyMaxWeight(id: date, date: date, maxWeight: maxWeight)
            }
        } catch {
            print("获取每日最大重量失败:\(error)")
        }
    }
}
  1. 修改ExerciseDetailView使用数据管理类:
struct ExerciseDetailView: View {
    @StateObject private var dataManager: ExerciseDataManager
    var exercise: String
    
    init(exercise: String) {
        self.exercise = exercise
        self._dataManager = StateObject(wrappedValue: ExerciseDataManager(exerciseName: exercise))
    }
    
    var body: some View {
        NavigationView {
            ScrollView {
                if #available(iOS 16.0, *) {
                    Chart(dataManager.dailyMaxWeights) { item in
                        LineMark(x: .value("日期", item.date),
                                 y: .value("最大重量", item.maxWeight)
                        )
                    }
                } else {
                    Text("需要iOS 16及以上版本才能查看图表")
                }
            }
            .navigationTitle(exercise)
        }
    }
}

内容的提问来源于stack exchange,提问作者Rachel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:20:47