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

API数据按今日/昨日分类的方案评估及优化咨询

问题描述

从API获取包含创建日期的数据,原实现是通过isMoreThan24HoursAgo函数判断创建时间是否超过24小时,在View的ForEach循环中逐个判断数据项,区分“今日”“昨日”分类展示。但存在两个问题:

  • 重复判断:每个数据项在两个分类模块中都要被判断一次
  • 空提示重复:空提示文本会随数据项数量重复显示

附现有代码:

struct TestView: View {
@StateObject var viewModel: ViewModel = ViewModel()

var body: some View {
    VStack {
        VStack(alignment: .leading) {
            HStack {
                Text("Today")
                    .font(.ubuntu(name: .ubuntuBold, size: 14))
                    .foregroundColor(Color.gray.opacity(0.6))
                    .padding(.vertical, 15)
                Spacer()
            }
            ScrollView(showsIndicators: false) {
                if let history = viewModel.history?.data?.data {
                    ForEach(history.prefix(2), id: \.self) { item in
                        if !viewModel.isMoreThan24HoursAgo(item.createdAt ?? "N/A") {
                            HistoryCard(historyModel: item)
                        } else {
                            Text("No recent history added.")
                        }
                    }
                }
            }
        }
        
        VStack(alignment: .leading) {
            HStack {
                Text("Yesterday")
                    .font(.ubuntu(name: .ubuntuBold, size: 14))
                    .foregroundColor(Color.gray.opacity(0.6))
                    .padding(.vertical, 15)
                Spacer()
            }
            ScrollView(showsIndicators: false) {
                if let history = viewModel.history?.data?.data {
                    ForEach(history.prefix(2), id: \.self) { item in
                        if viewModel.isMoreThan24HoursAgo(item.createdAt ?? "N/A") {
                            HistoryCard(historyModel: item)
                        } else {
                            Text("No recent history added.")
                        }
                    }
                }
            }
        }
        
        Spacer()
    }
}
}

日期判断函数:

func isMoreThan24HoursAgo(_ dateString: String) -> Bool {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
    
    guard let date = dateFormatter.date(from: dateString) else {
        return false
    }
    
    let calendar = Calendar.current
    let now = Date()
    let components = calendar.dateComponents([.hour], from: date, to: now)
    
    if let hours = components.hour, hours > 24 {
        return true
    } else {
        return false
    }
}
解答

一、分类方式是否合理?

用“是否超过24小时”区分“今日”“昨日”逻辑不够严谨:

  • 若当前时间为晚上11点,24小时前是前一天晚上11点,前一天0点到11点的内容会被归为“昨日”,但实际距离当前不足24小时,不符合用户对“今日/昨日”的直觉认知
  • 更合理的分类应该基于日历日期:“今日”指当前日历日的所有数据,“昨日”指前一个日历日的所有数据,完全贴合用户日常认知

如果业务明确要求用“24小时区间”划分,当前逻辑可行,但需明确该逻辑和常规“今日/昨日”概念的差异,对齐产品需求。

二、优化方案(解决重复判断+空提示重复问题)

1. 提前预处理数据,避免重复判断

在ViewModel中一次性完成数据分类,将数据拆分为“今日组”和“昨日组”,View层直接使用分组后的数据,无需重复判断:

  • 在ViewModel中添加两个数组属性存储分组数据
  • API数据返回后,执行一次分类逻辑,后续View直接取用分组结果

2. 重构视图逻辑,解决空提示重复问题

空提示应在分组数据为空时显示,而非在ForEach循环中逐个判断,确保空提示仅显示一次。

3. 优化日期判断函数

  • 避免每次调用创建DateFormatter(Formatter创建开销较大),将其设为静态属性复用
  • 若按日历日期分类,直接使用Calendar的isDateInToday和isDateInYesterday方法,更准确且符合用户直觉

优化后的完整代码

ViewModel部分

class ViewModel: ObservableObject {
    @Published var history: HistoryResponse? // 替换为你的API响应模型
    // 预处理后的分组数据
    @Published var todayItems: [HistoryItem] = []
    @Published var yesterdayItems: [HistoryItem] = []
    
    // 静态DateFormatter,避免重复创建
    private static let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        return formatter
    }()
    
    func fetchHistory() {
        // 此处添加API请求逻辑,获取数据后调用分类方法
        if let data = history?.data?.data {
            categorizeHistoryItems(data)
        }
    }
    
    private func categorizeHistoryItems(_ items: [HistoryItem]) {
        let calendar = Calendar.current
        
        todayItems = items.filter { item in
            guard let dateStr = item.createdAt,
                  let date = Self.dateFormatter.date(from: dateStr) else {
                return false
            }
            // 按日历今日分类,符合用户直觉
            return calendar.isDateInToday(date)
            // 若坚持用24小时区间,替换为:
            // return !isMoreThan24HoursAgo(dateStr)
        }
        
        yesterdayItems = items.filter { item in
            guard let dateStr = item.createdAt,
                  let date = Self.dateFormatter.date(from: dateStr) else {
                return false
            }
            // 按日历昨日分类
            return calendar.isDateInYesterday(date)
            // 若坚持用24小时区间,替换为:
            // return isMoreThan24HoursAgo(dateStr)
        }
    }
    
    // 若保留24小时判断逻辑,优化后的版本
    private func isMoreThan24HoursAgo(_ dateString: String) -> Bool {
        guard let date = Self.dateFormatter.date(from: dateString) else {
            return false
        }
        let twentyFourHoursAgo = Date().addingTimeInterval(-24 * 60 * 60)
        return date < twentyFourHoursAgo
    }
}

View部分

struct TestView: View {
    @StateObject var viewModel: ViewModel = ViewModel()
    
    var body: some View {
        VStack {
            // 今日分组视图
            SectionView(title: "Today", items: viewModel.todayItems)
            
            // 昨日分组视图
            SectionView(title: "Yesterday", items: viewModel.yesterdayItems)
            
            Spacer()
        }
        .onAppear {
            viewModel.fetchHistory()
        }
    }
}

// 提取复用的分组视图,减少代码冗余
struct SectionView: View {
    let title: String
    let items: [HistoryItem]
    
    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                Text(title)
                    .font(.ubuntu(name: .ubuntuBold, size: 14))
                    .foregroundColor(Color.gray.opacity(0.6))
                    .padding(.vertical, 15)
                Spacer()
            }
            
            ScrollView(showsIndicators: false) {
                if items.isEmpty {
                    Text("No recent history added.")
                        .foregroundColor(.gray)
                        .padding(.vertical)
                } else {
                    // 若需限制显示数量,使用prefix(2)
                    ForEach(items.prefix(2), id: \.self) { item in
                        HistoryCard(historyModel: item)
                    }
                }
            }
        }
        .padding(.horizontal)
    }
}

内容的提问来源于stack exchange,提问作者Luka Šalipur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 13:06:03