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

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,导致集合认为这是两个不同元素,点击时无法匹配移除,反而重复添加。

解决方案

  1. 严格指定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) 
                })
            }
    }
    
  2. 优化onChange回调
    直接使用newValue参数,避免读取状态变量的延迟问题:

    .onChange(of: selectedDates) { oldValue, newValue in
        saveDates(dates: newValue)
    }
    
  3. 可选:自定义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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 23:22:33