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

SwiftUI中ObservableObject搭配DatePicker的实现优化咨询

实现方案

第一步:改造DateHandler直接遵守ObservableObject

不需要额外的包装类,只要在存储属性的didSet中手动发送视图更新通知即可,兼容你已有的自定义getter/setter逻辑:

import SwiftUI

class DateHandler: ObservableObject {
    var date1 : Date {
        didSet{
            objectWillChange.send() // 手动通知视图属性变更
            print("StartDate: \(date1)")
        }
    }
    var date2 : Date {
        didSet{
            objectWillChange.send() // 手动通知视图属性变更
            print("EndDate: \(date2)")
        }
    }
    
    var startDate:Date {
        get{
            return date1
        }
        set(newValue){
            let adjustedDate = toLocalTime(date: newValue)
            // 直接把日期校验逻辑内聚到这里,不用放到视图层
            guard adjustedDate < endDate else { return }
            date1 = adjustedDate
        }
    }
    
    var endDate:Date {
        get{
            return date2
        }
        set(newValue){
            let adjustedDate = addOneDay(date: toLocalTime(date: newValue))
            guard adjustedDate > startDate else { return }
            date2 = adjustedDate
        }
    }
    
    init(){
        self.date1 = Date()
        self.date2 = addOneDay(date: toLocalTime(date: Date())) // 初始化默认结束日期比开始晚一天
    }
    
    //Customize time zone
    func toLocalTime(date : Date) -> Date {
        let calendar = Calendar.current
        let timezone = TimeZone.current
        let seconds = TimeInterval(timezone.secondsFromGMT(for: date))
        let newDate = calendar.date(bySettingHour: 00, minute: 00, second: 00, of: date)
        let dateLocalTimezone = Date(timeInterval: seconds, since: newDate!)
        return dateLocalTimezone
    }
    
    func addOneDay(date : Date) -> Date {
        let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: date)
        return tomorrow!
    }
}

第二步:简化视图代码,省略中转State变量

现在可以直接把DatePicker绑定到DateHandler的属性,不需要额外的辅助变量和onChange/onAppear逻辑:

struct ContentView: View {
    // iOS14+用@StateObject,低版本用@ObservedObject即可
    @StateObject var dateHandler = DateHandler()

    var body: some View {
        VStack(spacing: 20) {
            DatePicker("Date1", selection: Binding(
                get: { dateHandler.startDate },
                set: { dateHandler.startDate = $0 }
            ), displayedComponents: .date)
            
            DatePicker("Date2", selection: Binding(
                get: { dateHandler.endDate },
                set: { dateHandler.endDate = $0 }
            ), displayedComponents: .date)
        }
        .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

方案说明

  • 直接让DateHandler遵守ObservableObject,利用objectWillChange.send()手动触发变更通知,解决了自定义getter/setter无法使用@Published的问题,完全省略了冗余的DateHandlerHelper包装类
  • 直接通过Binding构造器绑定DatePicker到DateHandler的属性,不再需要中转的辅助State变量
  • 把开始日期不能晚于结束日期的校验逻辑内聚到DateHandler内部,逻辑更聚合,视图层更干净

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 07:15:00