Swift MultiDatePicker加载Firebase日期后无法识别已选日期
问题:从Firebase加载日期到MultiDatePicker后,取消选择功能失效
从Firebase加载日期到MultiDatePicker后,点击已选中的日期无法将其从selectedDates集合中移除,反而会重复添加。无Firebase数据时,日期的选择/取消功能正常,仅在加载数据后出现该问题。
相关代码
视图代码
VStack { MultiDatePicker("Select dates", selection: $selectedDates) .padding() .onChange(of: selectedDates) { oldValue, newValue in saveDates(dates: selectedDates) } List(savedDates, id: \.self) { date in Text("\(date, formatter: dateFormatter)") } .listStyle(.plain) } .onAppear { loadSavedDates() }
状态变量
@State var selectedDates: Set<DateComponents> = []
Firebase加载日期代码
func loadSavedDates() { let db = Firestore.firestore() let uid = try! AuthenticationManager.shared.getAuthenticatedUser().uid print("User ID: \(uid)") print(widget.id.uuidString) db.collection("spaces") .document(spaceId) .collection("dates") .document(widget.id.uuidString)//widget.id.uuidString .getDocument {document, error in if let document = document { if let dateStrings = document.data()?[uid] as? [String] { let dateFormatter = DateFormatter() dateFormatter.dateStyle = .medium self.savedDates = dateStrings.compactMap { dateFormatter.date(from: $0) }.sorted() let calendar = Calendar.current self.selectedDates = Set(self.savedDates.map { calendar.dateComponents([.year, .month, .day], from: $0) }) for component in selectedDates { print(component.isValidDate) } } } else { print("Document does not exist") } } }
问题原因与解决方案
核心原因
DateComponents的相等性判断依赖于所有包含的组件。你从Firebase加载转换的DateComponents,可能隐式包含了时区、时分秒等未显式指定的组件,而MultiDatePicker内部生成的DateComponents仅包含.year、.month、.day,导致集合认为这是两个不同元素,点击时无法匹配移除,反而重复添加。
解决方案
严格指定
DateComponents的组件范围
转换日期时,确保只提取.year、.month、.day三个组件,避免多余组件干扰。同时给DateFormatter显式设置时区,避免解析时的时区差异。修改后的加载代码:
func loadSavedDates() { let db = Firestore.firestore() guard let uid = try? AuthenticationManager.shared.getAuthenticatedUser().uid else { return } db.collection("spaces") .document(spaceId) .collection("dates") .document(widget.id.uuidString) .getDocument { document, error in guard let document = document, document.exists else { print("Document does not exist") return } guard let dateStrings = document.data()?[uid] as? [String] else { return } let dateFormatter = DateFormatter() dateFormatter.dateStyle = .medium // 显式设置时区,避免解析时的时区偏移 dateFormatter.timeZone = TimeZone(identifier: "UTC") self.savedDates = dateStrings.compactMap { dateFormatter.date(from: $0) }.sorted() let calendar = Calendar.current // 严格只提取年、月、日组件 self.selectedDates = Set(self.savedDates.map { calendar.dateComponents([.year, .month, .day], from: $0) }) } }优化
onChange回调
直接使用newValue参数,避免读取状态变量的延迟问题:.onChange(of: selectedDates) { oldValue, newValue in saveDates(dates: newValue) }可选:自定义
DateComponents的相等性判断
如果上述方法仍无效,可以扩展DateComponents,手动实现基于年/月/日的相等性和哈希值:extension DateComponents: Hashable { public static func == (lhs: DateComponents, rhs: DateComponents) -> Bool { return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day } public func hash(into hasher: inout Hasher) { hasher.combine(year) hasher.combine(month) hasher.combine(day) } }
内容的提问来源于stack exchange,提问作者Joshua Shen
相关产品推荐
相关产品推荐

