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

如何修复iOS日历事件保存时出现的「No start date has been set」(EKErrorDomain Code=2)错误?

修复EKErrorDomain Code=2 "No start date has been set" 问题

这个问题的核心原因很明确:你把事件的startDate和endDate赋值操作放到了DispatchQueue.main.async闭包里,但保存事件的代码却在闭包外面同步执行。

咱们捋一捋执行顺序:当eventStore.requestAccess的回调触发后,你创建了EKEvent实例,接着立刻调用DispatchQueue.main.async把属性赋值的任务抛给主队列,然后马上就执行eventStore.save(...)。这时候主队列的闭包还没来得及执行,event的startDate和endDate还是默认的nil,系统自然就会抛出“没有设置开始日期”的错误——哪怕你代码里写了赋值逻辑也没用,因为时机不对!

下面给你两种修复方案,按需选择:

方案一:去掉不必要的主队列切换(推荐)

如果你的属性赋值不需要依赖UI控件(比如例子里直接用Date()生成日期),完全不需要切换到主队列,直接同步赋值就行:

func saveTaskInCalendar() { 
    let eventStore : EKEventStore = EKEventStore() 
    eventStore.requestAccess(to: .event) { (granted, error) in 
        guard granted, error == nil else {
            print("failed to save event with error : \(String(describing: error)) or access not granted")
            return
        }
        
        let event = EKEvent(eventStore: eventStore) 
        // 直接同步赋值,不需要主队列
        event.title = "Test" 
        event.startDate = Date() 
        // 建议给结束时间设置一个合理的时长,比如1小时,避免和开始时间完全相同
        event.endDate = Date().addingTimeInterval(3600)
        event.calendar = eventStore.defaultCalendarForNewEvents 
        
        do { 
            try eventStore.save(event, span: .thisEvent) 
            // 如果需要更新UI(比如提示保存成功),再切换到主队列
            DispatchQueue.main.async {
                // 这里写UI相关操作,比如弹出提示框
            }
        } catch let error as NSError { 
            print("failed to save event with error : \(error)") 
        } 
    } 
}

方案二:把保存操作也移到主队列里

如果你的属性赋值必须依赖UI(比如从文本框、日期选择器获取内容),那就把保存事件的代码也放到DispatchQueue.main.async闭包里,保证赋值完成后再执行保存:

func saveTaskInCalendar() { 
    let eventStore : EKEventStore = EKEventStore() 
    eventStore.requestAccess(to: .event) { (granted, error) in 
        guard granted, error == nil else {
            print("failed to save event with error : \(String(describing: error)) or access not granted")
            return
        }
        
        let event = EKEvent(eventStore: eventStore) 
        DispatchQueue.main.async { 
            event.title = "Test" 
            event.startDate = Date() 
            event.endDate = Date().addingTimeInterval(3600)
            event.calendar = eventStore.defaultCalendarForNewEvents 
            
            do { 
                try eventStore.save(event, span: .thisEvent)
                // 保存成功后的UI操作
            } catch let error as NSError { 
                print("failed to save event with error : \(error)") 
            } 
        } 
    } 
}

另外补充个小建议:尽量让endDate晚于startDate,虽然系统对相同的日期也能处理,但设置一个合理的时长(比如1小时)会更符合日历事件的逻辑,也能避免一些潜在的奇怪问题。

内容的提问来源于stack exchange,提问作者Мария G

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 15:29:06