一、关于系统日历和提醒事宜
iOS系统自带的Calendar应用非常强大,用户可以在其中添加日程事件,并且其提供了接口供其他应用进行调用,可以向日历中进行事件的读取和写入。
首先,Canlendar应用默认创建了几个类型的日历,用户也可以根据需要创建自定义的日历,如下图:
在上图中,US Holidays、Birthdays、Siri Found in Apps和Calendar是默认创建的几个日历,Custom是自定义的日历,当用户新建日历事件时,需要关联到某个日历,如下:
对于系统的Reminders,其主要作用是提供事件列表,用户可以向事件列表中添加提醒事件,同样,提供默认创建了两个事件列表,用户也可以根据需要自行创建新的事件列表,如下图:
使用日历和提醒事宜这两个应用,可以提高生活工作效率,例如邮件应用通过与日历的交互可以将会议邮件添加到用户的日程中,EventKit框架则是提供了接口与这两个应用进行交互。
二、EventKit框架概览
EventKit核心的用途是配合系统的日历与提醒应用,对事件提醒进行管理,其中核心类即结构如下:
从图中可以看出,重要数据的管理类为EKEventStore,其他类都是用来描述对应的数据,下面会一一介绍。
三、日历事件操作
第三方应用需要操作用户的日历事件,需要获取用户授权,首先需要在info.plist文件中添加如下权限请求字段:
获取当前Calendars应用中定义的日历示例代码如下:
#import "ViewController.h"
#import <EventKit/EventKit.h>
@interface ViewController ()
@property (nonatomic, strong) EKEventStore *eventStore;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化
self.eventStore = [[EKEventStore alloc] init];
// 请求权限
[self.eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) {
if (!granted) {
NSLog(@"拒绝访问");
} else {
// 获取所有日历
NSArray *calendars = [self.eventStore calendarsForEntityType:EKEntityTypeEvent];
for (EKCalendar *calendar in calendars) {
NSLog(@"%@", calendar);
}
}
}];
}
@end
上面方法会获取到所有的日历,也可以通过来源来获取日历,后面会具体介绍。
使用如下代码可以添加新的日历,通常,第三方应用如果要向用户日历中添加事件,可以先添加一个新的日历:
- (void)createNewCalendar {
EKCalendar *calendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:self.eventStore];
for (EKSource *source in self.eventStore.sources) {
if (source.sourceType == EKSourceTypeLocal) {
// 设置来源为本地
calendar.source = source;
}
}
calendar.title = @"珲少的事项日历";//自定义日历标题
calendar.CGColor = [UIColor purpleColor].CGColor;//自定义日历颜色
NSError* error;
[_eventStore saveCalendar:calendar commit:YES error:&error];
}
效果如下图:
日历事件的查询需要构造NSPredicate对象,示例如下:
- (void)queryEvent {
for (EKCalendar *cal in [self.eventStore calendarsForEntityType:EKEntityTypeEvent]) {
if ([cal.title isEqualToString:@"珲少的事项日历"]) {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *oneMonthFromNowComponents = [[NSDateComponents alloc] init];
oneMonthFromNowComponents.month = 1;
NSDate *oneMonthFromNow = [calendar dateByAddingComponents:oneMonthFromNowComponents
toDate:[NSDate date]
options:0];
// 获取从今往后一个月的
NSPredicate*predicate = [self.eventStore predicateForEventsWithStartDate:[NSDate date] endDate:oneMonthFromNow calendars:@[cal]];
NSArray *eventArray = [self.eventStore eventsMatchingPredicate:predicate];
NSLog(@"%@", eventArray);
}
}
}
通过存储的相关接口,也可以对某个事件进行修改,或创建新的事件,示例如下:
- (void)createEvent {
EKCalendar *calen = nil;
for (EKCalendar *cal in [self.eventStore calendarsForEntityType:EKEntityTypeEvent]) {
if ([cal.title isEqualToString:@"珲少的事项日历"]) {
calen = cal;
}
}
EKEvent *event = [EKEvent eventWithEventStore:self.eventStore];
event.title = @"从应用创建的事件";
event.startDate = [NSDate date];
event.calendar = calen;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *oneMonthFromNowComponents = [[NSDateComponents alloc] init];
oneMonthFromNowComponents.hour += 1;
NSDate *endDate = [calendar dateByAddingComponents:oneMonthFromNowComponents
toDate:[NSDate date]
options:0];
event.endDate = endDate;
event.notes = @"备注";
[event setAllDay:NO];//设置全天
//保存事件
NSError *error = nil;
[self.eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&error];
NSLog(@"%@",error);
}
下面示例代码用来删除日历事件:
- (void)removeEvent {
for (EKCalendar *cal in [self.eventStore calendarsForEntityType:EKEntityTypeEvent]) {
if ([cal.title isEqualToString:@"珲少的事项日历"]) {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *oneMonthFromNowComponents = [[NSDateComponents alloc] init];
oneMonthFromNowComponents.month = 1;
NSDate *oneMonthFromNow = [calendar dateByAddingComponents:oneMonthFromNowComponents
toDate:[NSDate date]
options:0];
// 获取从今往后一个月的
NSPredicate*predicate = [self.eventStore predicateForEventsWithStartDate:[NSDate date] endDate:oneMonthFromNow calendars:@[cal]];
NSArray *eventArray = [self.eventStore eventsMatchingPredicate:predicate];
[self.eventStore removeEvent:eventArray.firstObject span:EKSpanThisEvent error:nil];
}
}
}