iOS日历相关操作--读取系统日历、添加事件到系统日历
1 读取系统日历
let eventStore = EKEventStore() let tempFormatter = NSDateFormatter() tempFormatter.dateFormat = "dd.MM.yyyy HH:mm" //获取一个时间段中的日历事件 let startDate = tempFormatter.dateFromString("10.08.2016 15:10")! let endDate = tempFormatter.dateFromString("12.08.2016 15:30")! let predicate = eventStore.predicateForEventsWithStartDate(startDate, endDate: endDate, calendars: [eventStore.defaultCalendarForNewEvents]) //获取这个时间段中的所有日程 let events = eventStore.eventsMatchingPredicate(predicate)
2 添加事件到系统日历
let eventStore = EKEventStore()
eventStore.requestAccessToEntityType(.Event) { (granted, error) in dispatch_async(dispatch_get_main_queue(), { if error != nil { //发生错误 } else if !granted { //不允许访问日历 } else { //创建事件 let event = EKEvent(eventStore: eventStore) event.title = "lallallallal" let tempFormatter = NSDateFormatter() tempFormatter.dateFormat = "dd.MM.yyyy HH:mm" //创建一个时间段的日历事件 event.startDate = tempFormatter.dateFromString("11.08.2016 15:20")! event.endDate = tempFormatter.dateFromString("11.08.2016 15:30")! //设置是否为全天事件 event.allDay = false //设置事件的提醒时间(相对时间)提前15分钟提醒 event.addAlarm(EKAlarm(relativeOffset: -60.0 * 15.0)) //设置事件的提醒时间(绝对时间) //event.addAlarm(EKAlarm(absoluteDate: NSDate(timeInterval: -60 * 15, sinceDate: event.startDate))) event.calendar = eventStore.defaultCalendarForNewEvents //保存事件,添加到日历中 do { try eventStore.saveEvent(event, span: .ThisEvent, commit: true) } catch { } } }) }
3 分析:
日历分为两类,一类用于存储事件的日历,一类用于存储提醒的日历。
EventKit库框架授权访问用户的日历app及提醒事项app。尽管是用两个不同的应用来显示用户的日历和提醒数据,但却是同一个框架来维护这份数据。同样地,存储这份数据的数据库叫做日历数据库,同时容纳日历和提醒信息。
事件库不但允许你的应用获取用户已经存在的日历及提醒数据,而且它可以让你的应用为任何日历创建新的事件和提醒。另外,事件库让用户可以编辑和删除他们的事件和提醒(整体叫做“日历项”)。如果日历数据库有来自你的应用外部的更改发生,事件库可以通过通知监测到,这样你的应用可以做出适当的响应。使用事件库对日历项所做的更改会自动地同步到相关的日历。
(1)读写日历数据库
你可以使用 EKEventStore
类从用户的日历数据库中获取、创建、编辑和删除事件。你可以获取匹配你提供的谓词的事件自定义的一组事件,或通过唯一标识获取一个单独的事件。你获取到一个事件后,可以使用 EKEvent
类的属性获取访问该事件相关的日历信息。同样的,你可以通过设置 EKEvent
类的属性来修改该事件的日历信息。
- 连接到事件库
在 iOS 5 及以后版本系统中,使用默认的初始化器:
let eventStore = EKEventStore()
在 iOS 6 及以后版本,你必须在事件库初始化后,使用
requestAccessToEntityType:completion:
方法请求使用用户的日历数据库。请求访问某个实体类型会异步提示用户允许或禁止你的应用使用他们的日历信息。你应该处理用户授权或禁止你的应用访问权的各种状况:eventStore.requestAccessToEntityType(.Event) { (granted, error) in
}EKEventStore
对象需要相对较大量的时间来初始化和释放。因此,你不应该为每一个事件相关的任务都初始化和释放事件库。相反,在你的应用加载时,初始化一个事件库,然后反复地使用这一个来确保连接一直可用。事件库实例不应该在其它事件开发包相对的对象释放前被释放,否则可能发生意想不到的状态。 - 获取事件
有两种方式获取事件。通过谓词或搜索查询获取,会返回零个或多个与给定查询匹配的事件。通过唯一标识获取会返回与给定标识相符的唯一的一个事件。
注意:从日历数据库获取事件并不一定按时间顺序返回。要通过日期排序EKEvent
对象的数组,可以在数组上调用sortedArrayUsingSelector:
方法,并提供compareStartDateWithEvent:
方法的选择器。 - 使用谓词
通常是要获得属于某一日期范围的事件。EKEventStore 的
eventsMatchingPredicate:
方法获取属于你提供的谓词中指定的日期范围的所有事件。
注意:尽管eventsMatchingPredicate:
方法接受一个NSPredicate
类型的参数,但你必须提供一个用
EKEventStore
的方法predicateForEventsWithStartDate:endDate:calendars:
创建的谓词。
你可以指定一个日历的子集来搜索,这需要传递一个EKCalendar
对象的数组作为predicateForEventsWithStartDate:endDate:calendars:
方法的 calendars 参数。你可以从事件库的calendarsForEntityType:
方法获得用户的不同类型的日历。如果传一个 nil 值,那么就是告诉这个方法获取用户的所有日历。
因为方法eventsMatchingPredicate:
是同步的,而你可能并不想在你的应用主线程中运行它。如果要异步执行的话,那么使用dispatch_async
函数或使用一个NSOperation
对象,就可以在另一个线程中运行该方法了。 - 使用唯一标识
如果你之前使用谓词获得了一个事件并知道它的唯一标识,那么你可以使用EKEventStore
的eventWithIdentifier:
方法来再次获取该事件。如果它是一个循环事件,那么这个方法就会返回第一次出现的该事件。你可以使用属性eventIdentifier
获得事件的唯一标识。 - 创建及编辑事件
使用 事件EKEvent
的eventWithEventStore: 方法创建一个新的事件。 - 保存和移除事件
提示:如果你的应用修改用户的日历数据库,它必须在这之前先从用户获得确认。应用在未得到用户的特定指示的情况下决不可能修改日历数据库。
你对事件的修改不是持久化的,直到你保存它们为止。使用
EKEventStore
的 saveEvent:span:commit:error: 方法保存你的修改到日历数据库中。如果你要从日历数据库移除事件,使用 EKEventStore 的 removeEvent:span:commit:error: 方法。无论你保存或移除事件,各自实现的方法都会自动所做的修改到该事件所属于的日历(CalDav、Exchange等等)。如果你保存一个循环事件,你可以通过给
saveEvent:span:commit:error:
方法的参数 span 指定EKSpanFutureEvents
来使你的更改应用到所有未来出现的该事件中。同样地,你也可以指定removeEvent:span:commit:error:
方法的 span 参数值为EKSpanFutureEvents
来移除一个事件的所有未来的出现。注意:如果你给 commit 参数传了 NO 值,那么要确保稍侯调用
commit:
方法以持久保存你的更改(译者注:默认传 YES 会立即持久保存更改)。