Contents

获取系统日历下的 Event 可以用

- (NSArray<EKEvent *> *)eventsMatchingPredicate:(NSPredicate *)predicate;

来得到其中 predicate 是用来表征筛选条件的,NSPredicate 这个词取得真好。

vt. 断定为…;使…基于
vi. 断言,断定
n. 谓语,述语
adj. 谓语的;述语的

然而在 EKEvent 中没有关于 Event type 的属性,这个属性的定义在 EKTypes.h 里

typedef NS_ENUM(NSInteger, EKSourceType) {
    EKSourceTypeLocal,
    EKSourceTypeExchange,
    EKSourceTypeCalDAV,
    EKSourceTypeMobileMe,
    EKSourceTypeSubscribed,
    EKSourceTypeBirthdays
};

以及

typedef NS_ENUM(NSInteger, EKCalendarType) {
    EKCalendarTypeLocal,
    EKCalendarTypeCalDAV,
    EKCalendarTypeExchange,
    EKCalendarTypeSubscription,
    EKCalendarTypeBirthday
};

EKSourceTypeEKSource 中 sourceType 的值,而 EKSourceEKCalendar 的属性;
EKCalendarTypeEKCalendar 属性 type 的值。所以看起来无论从一开始的输入还是最终的输出都没有办法找到跟以上两个枚举的关系链条。于是还是从输入开始——注意力放到美妙的单词 predicate 上,直觉告诉我可以在这里操作。

于是很快找到

- (NSPredicate *)predicateForEventsWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate calendars:(nullable NSArray<EKCalendar *> *)calendars;

这里面有个参数是 EKCalendar 的数组,有了它必然就能塞个 EKCalendarType 或者 EKSourceType 条件进去进而得到筛选后的结果。

于是

###方法一:(此方法不可取)

EKEventStore *eventStore = [[EKEventStore alloc] init];
NSMutableArray <EKCalendar *> *calendars = [@[] mutableCopy];

for (EKSource *source in eventStore.sources) {
    if (source.sourceType == EKSourceTypeSubscribed) {//我需要把 EKSourceTypeSubscribed 剔除
        continue;
    }
    EKCalendar *calendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:eventStore];
    [calendars addObject:calendar]; 
  }

NSPredicate *predicate = [eventStore predicateForEventsWithStartDate:[NSDate dateWithTimeIntervalSinceNow:-3600 * 24 * 365 * 10] 
                                                             endDate:[NSDate dateWithTimeIntervalSinceNow:3600 * 24 * 365 * 10] 
                                                           calendars:[calendars copy]];
NSArray *systemEvents = [eventStore eventsMatchingPredicate:predicate];

###方法二

- (NSArray<EKCalendar *> *)calendarsForEntityType:(EKEntityType)entityType

这个函数会返回指定的 EKCalendar 的数组,只需要把相应的取出来就行啦。

EKEventStore *eventStore = [[EKEventStore alloc] init];
NSMutableArray <EKCalendar *> *calendars = [@[] mutableCopy];

for (EKCalendar *calendar in [eventStore calendarsForEntityType:EKEntityTypeEvent]) {
    if (calendar.source.sourceType == EKSourceTypeSubscribed) {
       continue;
   }
   [calendars addObject:calendar];
}

NSPredicate *predicate = [eventStore predicateForEventsWithStartDate:[NSDate dateWithTimeIntervalSinceNow:-3600 * 24 * 365 * 10] 
                                                             endDate:[NSDate dateWithTimeIntervalSinceNow:3600 * 24 * 365 * 10] 
                                                           calendars:[calendars copy]];
NSArray *systemEvents = [eventStore eventsMatchingPredicate:predicate];

###总结

两个方法中,第一个是根据 EKEventStroresources 做一次遍历直接构造一个 Calendar 出来但是有一个严重的问题,这个 calender 并没有被指定是哪种类型的是不可靠的。
打印出来的结果也是符合我的判断,构造的所有 calendar 的类型都是 Local 的。所以我猜测

[EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:eventStore]

构造的 calendar 取的是 eventStore.sources[0] 的值。故而,方法一不可取。
方法二则没有这个问题,取出来的都是各个类型的 calendar 符合要求。

 2016-02-28 14:59:15.896 foo[2604:945656] calendar is EKCalendar <0x128f89ee0> {title = 中国假日 (只读); type = Exchange; allowsModify = YES; color = #FFCC00;}
2016-02-28 14:59:15.896 foo[2604:945656] calendar is EKCalendar <0x128f88960> {title = Birthdays; type = Birthday; allowsModify = NO; color = #8295AF;}
2016-02-28 14:59:15.896 foo[2604:945656] calendar is EKCalendar <0x128f89710> {title = yu 的日历; type = Exchange; allowsModify = YES; color = #FF2968;}
2016-02-28 14:59:15.897 foo[2604:945656] calendar is EKCalendar <0x128f89110> {title = Work; type = CalDAV; allowsModify = YES; color = #CC73E1;}
2016-02-28 14:59:15.897 foo[2604:945656] calendar is EKCalendar <0x128f895b0> {title = 生日日历 (只读); type = Exchange; allowsModify = YES; color = #A2845E;}
2016-02-28 14:59:15.897 foo[2604:945656] calendar is EKCalendar <0x128f89b00> {title = 中国农历 (只读); type = Exchange; allowsModify = YES; color = #1BADF8;}
2016-02-28 14:59:15.897 foo[2604:945656] calendar is EKCalendar <0x128f89390> {title = Home; type = CalDAV; allowsModify = YES; color = #1BADF8;}

根据这些结果我发现 EKCalendar 其实就是图中每个有红勾勾 cell 代表的实例。
EKEventStore 就是整个日历了。

Contents