SwiftUI中筛选Cloud Firestore内当前日期在双时间戳间的日历事件
解决方案
1. 优化数据模型(补充Identifiable必需字段)
原Calendar结构体缺少Identifiable协议要求的id字段,同时为避免与系统Calendar类冲突,重命名结构体并优化解析逻辑:
import FirebaseFirestoreSwift struct CalendarEvent: Decodable, Identifiable { @DocumentID var id: String? // 自动映射Firestore文档ID var title: String = "" var datebegin: Date = Date() var dateend: Date = Date() }
2. Firestore端精准筛选(减少客户端数据量)
直接在数据库查询阶段过滤出当前时间处于datebegin和dateend之间的文档,比全量拉取后再过滤更高效:
class CalendarViewModel: ObservableObject { let db = Firestore.firestore() @Published var events = [CalendarEvent]() init() { fetchFilteredEvents() } func fetchFilteredEvents() { let now = Date() db.collection("calendar") // 筛选条件:当前时间 >= datebegin 且 当前时间 <= dateend .whereField("datebegin", isLessThanOrEqualTo: now) .whereField("dateend", isGreaterThanOrEqualTo: now) .getDocuments { snapshot, error in guard let snapshot = snapshot, error == nil else { print("拉取数据失败:\(error?.localizedDescription ?? "未知错误")") return } // 用FirestoreDecoder自动解析文档,替代手动赋值 let events = snapshot.documents.compactMap { doc in try? doc.data(as: CalendarEvent.self) } DispatchQueue.main.async { self.events = events } } } }
3. 客户端分组与排序
在View中实现按星期几分组、按星期顺序排序的逻辑:
struct HomeView: View { @EnvironmentObject var viewModel: CalendarViewModel // 预设星期顺序,保证分组按周一到周日排列 private let weekOrder = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"] // 静态日期格式化器,避免重复创建提升性能 private static let weekdayFormatter: DateFormatter = { let formatter = DateFormatter() formatter.locale = Locale(identifier: "zh_CN") formatter.dateFormat = "EEEE" return formatter }() // 计算属性:处理分组与排序后的事件列表 private var groupedEvents: [(weekday: String, events: [CalendarEvent])] { // 按星期几分组事件 let groupedDict = Dictionary(grouping: viewModel.events) { event in Self.weekdayFormatter.string(from: event.datebegin) } // 按预设星期顺序排序分组,同时每组内事件按开始时间升序排列 return weekOrder.compactMap { weekday in guard let events = groupedDict[weekday] else { return nil } let sortedEvents = events.sorted { $0.datebegin < $1.datebegin } return (weekday, sortedEvents) } } var body: some View { List(groupedEvents, id: \.weekday) { group in Section(header: Text(group.weekday).font(.headline)) { ForEach(group.events) { event in Text(event.title) } } } } }
关键注意事项
- 确保Firestore中
datebegin和dateend字段为Timestamp类型,否则查询条件会失效; - 若需要实时更新事件,可将
getDocuments替换为addSnapshotListener,实现数据库变更的实时监听; - 若需支持多语言,可调整
DateFormatter的locale参数。
内容的提问来源于stack exchange,提问作者user18175514
相关产品推荐
相关产品推荐

