Swift/SwiftUI中如何获取指定日历的当日事件?
解决方案
你的代码存在两个关键问题:一是异步获取事件的逻辑错误导致UI无法拿到数据,二是未实现指定日历的筛选。以下是修复后的完整代码,附带关键修改说明:
import SwiftUI import EventKit struct TodayView: View { // 用@State存储事件数组,更新时自动触发UI刷新 @State private var events: [EKEvent] = [] // 保持EKEventStore实例,避免重复创建 private let eventStore = EKEventStore() var body: some View { NavigationView { ZStack { Color.gray.opacity(0.1) // 示例背景色,可替换为你自己的background定义 ScrollView(.vertical) { VStack(spacing: 12) { if events.isEmpty { Text("今日无课程事件") .foregroundColor(.secondary) .padding() } else { ForEach(events, id: \.self) { event in VStack(alignment: .leading) { Text(event.title) .font(.headline) Text(event.startDate.formatted(date: .omitted, time: .shortened)) .font(.caption) .foregroundColor(.secondary) } .padding() .background(Color.white) .cornerRadius(8) .shadow(radius: 2) } } } .padding() } } .navigationTitle("今日课程") .onAppear(perform: fetchTodayClassEvents) // 视图出现时触发事件获取 } } private func fetchTodayClassEvents() { eventStore.requestAccess(to: .event) { [weak self] granted, error in guard let self = self else { return } if let error = error { print("权限请求出错:\(error.localizedDescription)") return } guard granted else { print("日历权限被拒绝,请在设置中开启") DispatchQueue.main.async { self.events = [] } return } // 1. 找到名为"All Classes"的目标日历 guard let targetCalendar = self.eventStore.calendars(for: .event).first(where: { $0.title == "All Classes" }) else { print("未找到名为All Classes的日历") DispatchQueue.main.async { self.events = [] } return } // 2. 构造当日的时间范围(从今日0点到明日0点) let calendar = Calendar.current let startOfDay = calendar.startOfDay(for: Date()) let endOfDay = calendar.date(byAdding: .day, value: 1, to: startOfDay)! // 3. 创建仅查询目标日历的事件谓词 let predicate = self.eventStore.predicateForEvents( withStart: startOfDay, end: endOfDay, calendars: [targetCalendar] ) // 4. 获取匹配的事件并更新UI let fetchedEvents = self.eventStore.events(matching: predicate) // 按开始时间排序事件 let sortedEvents = fetchedEvents.sorted { $0.startDate < $1.startDate } DispatchQueue.main.async { self.events = sortedEvents } } } } // 预览 struct TodayView_Previews: PreviewProvider { static var previews: some View { TodayView() } }
关键修改说明
异步逻辑修复:
移除全局变量,改用@State private var events存储事件,异步获取完成后在主线程更新该变量,SwiftUI会自动刷新视图。
用onAppear触发事件获取,替代init中执行,确保视图初始化完成后再处理权限和数据请求。指定日历筛选:
通过eventStore.calendars(for: .event)获取所有可访问的事件日历,再用first(where:)筛选出标题为"All Classes"的日历。
创建predicateForEvents时,将calendars参数设为目标日历数组,实现仅查询该日历下的事件。时间范围优化:
把原来的跨三天范围改成精确的当日区间(今日0点到明日0点),避免查询到非当日的事件。异常与体验优化:
添加事件为空时的提示文本,给事件增加样式和时间显示,同时处理权限被拒绝、找不到目标日历等异常场景。
内容的提问来源于stack exchange,提问作者Tanner George
相关产品推荐
相关产品推荐

