使用EventKit搜索iOS日历中备注含指定文本的事件的实现方案
iOS日历按备注内容检索事件的实现方案
你无法直接通过自定义
NSPredicate在EKEventStore查询阶段完成备注匹配,苹果EventKit框架的events(matching:)方法仅支持通过predicateForEvents(withStart:end:calendars:)生成的内置谓词进行日期、归属日历维度的筛选,其余属性(包括备注、标题、位置等)的筛选都需要在拿到查询结果后二次过滤。
注意:执行查询前需要先向用户申请日历访问权限,通过requestAccess(to:completion:)方法完成权限校验,否则查询会返回空结果。
实现步骤
步骤1:构造全范围日期的查询谓词
不需要限制日期的话,可以直接用系统提供的极大范围日期distantPast(遥远过去)和distantFuture(遥远未来)作为时间区间边界,覆盖所有存在的日历事件:
import EventKit let store = EKEventStore() // 构造覆盖所有时间的查询谓词,calendars传nil代表查询所有日历 let allEventPredicate = store.predicateForEvents(withStart: .distantPast, end: .distantFuture, calendars: nil) // 获取符合时间范围的所有事件 let allEvents = store.events(matching: allEventPredicate)
步骤2:二次过滤备注包含指定文本的事件
用Swift的filter方法匹配notes属性,可根据需求开启大小写忽略、重音忽略等选项:
let searchText = "my search text" // 筛选备注包含搜索文本的事件,[c]表示忽略大小写,[d]表示忽略重音符号 let matchedEvents = allEvents.filter { event in guard let note = event.notes else { return false } return note.range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil }
最高效实现优化建议
- 如果明确只需要查询部分日历的事件,不要给
calendars参数传nil,传入指定的EKCalendar数组,减少初始查询返回的事件数量 - 事件数量较多时,把查询和过滤逻辑放到全局后台队列执行,完成后再切回主线程更新UI,避免阻塞主线程
- 如果需要频繁执行相同搜索,可将查询到的事件缓存到本地,下次搜索直接走缓存过滤,不需要重复调用
EventKit接口
内容的提问来源于stack exchange,提问作者user3386180
相关产品推荐
相关产品推荐

