最近手頭上一個(gè)日程管理的項(xiàng)目里有一個(gè)功能是做事務(wù)提醒的齿椅,原本是想用本地推送來實(shí)現(xiàn)绵估,但是無奈本地推送數(shù)量有限制脂男,最多不能超過64條。如果改用遠(yuǎn)程推送來實(shí)現(xiàn)融击,那是最好的了,但是資源雳窟、條件不是很完備(畢竟是學(xué)生項(xiàng)目尊浪,要申請(qǐng)開發(fā)者賬號(hào)還得增加后臺(tái)同學(xué)工作量等等),最后選擇了用系統(tǒng)日歷來完成封救。在此做了一些總結(jié)拇涤,方便日后查閱。
了解EventKit框架
事件庫框架授權(quán)訪問用戶的 Calendar.app 和 Reminders.app 應(yīng)用的信息誉结。盡管是用兩個(gè)不同的應(yīng)用顯示用戶的日歷和提醒數(shù)據(jù)鹅士,但確是同一個(gè)框架維護(hù)這份數(shù)據(jù)。他們使用相同的庫(EKEventStore)處理數(shù)據(jù)惩坑。
該框架除了允許檢索用戶已經(jīng)存在的calendar和reminder數(shù)據(jù)外掉盅,還允許創(chuàng)建新的事件和提醒。更高級(jí)的任務(wù)以舒,諸如添加鬧鐘或指定循環(huán)事件趾痘,也可以使用事件庫完成。
使用
準(zhǔn)備
在項(xiàng)目中導(dǎo)入EventKit框架和EventKitUI框架
在使用到這個(gè)框架的文件中import進(jìn)來:
#import <EventKit/EventKit.h>
#import <EventKitUI/EventKitUI.h>
創(chuàng)建一個(gè)事件庫實(shí)例
EKEventStore *eventStore = [[EKEventStore alloc] init];
因?yàn)镋KEventStore就像數(shù)據(jù)庫一樣蔓钟,頻繁的開啟永票,關(guān)閉會(huì)影響效率,所以如果你的程序需要頻繁操作日歷和提醒滥沫,建議僅生成該對(duì)象一次侣集,僅用一個(gè)對(duì)象進(jìn)行操作。因此項(xiàng)目里面我單獨(dú)寫了一個(gè)類封裝對(duì)日歷的操作兰绣,并用單例創(chuàng)建EKEventStore實(shí)例世分。
授權(quán)
iOS10以后獲得授權(quán)要在plist文件中進(jìn)行設(shè)置:添加權(quán)限字符串訪問日歷:NSCalendarsUsageDescription 訪問提醒事項(xiàng):NSRemindersUsageDescription
EKEntityType有兩類
EKEntityTypeEvent日歷事件 , EKEntityTypeReminder//提醒事項(xiàng)
- (void)calendarAuthority{
//獲取授權(quán)狀態(tài)
EKAuthorizationStatus eventStatus = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
//用戶還沒授權(quán)過
if(eventStatus ==EKAuthorizationStatusNotDetermined){
//提示用戶授權(quán),調(diào)出授權(quán)彈窗
[[[EKEventStore alloc]init] requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) {
if(granted){
NSLog(@"允許");
}else{
NSLog(@"拒絕授權(quán)");
}
}];
}
//用戶授權(quán)不允許
else if (eventStatus == EKAuthorizationStatusDenied){
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"當(dāng)前日歷服務(wù)不可用" message:@"您還沒有授權(quán)本應(yīng)用使用日歷,請(qǐng)到 設(shè)置 > 隱私 > 日歷 中授權(quán)" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
[alert addAction:action];
[self presentViewController:alert animated:YES completion:nil];
}
}
//還有兩種授權(quán)狀態(tài):
//EKAuthorizationStatusAuthorized用戶已經(jīng)允許授權(quán)
//EKAuthorizationStatusRestricted,未授權(quán)缀辩,且用戶無法更新臭埋,如家長(zhǎng)控制情況下
檢查授權(quán)狀態(tài)我們使用的是EKEventStore authorizationStatusForEntityType:類方法,而調(diào)出系統(tǒng)日歷事件授權(quán)彈窗使用的卻是EKEventStore的實(shí)例方法requestAccessToEntityType:
找到對(duì)應(yīng)的日歷源
日歷源它是EKSource的實(shí)例對(duì)象,可以理解為是按照日歷類型去分類的一些組雌澄。在模擬器下:
在這個(gè)圖里斋泄,我們看到有兩個(gè)日歷源,一個(gè)是“ON MY IPHONE”另一個(gè)是"OTHER"镐牺。這里我們打個(gè)斷點(diǎn)查看所有日歷源:
可以看到日歷數(shù)據(jù)庫中第一個(gè)日歷源的真正名稱為Default(是一個(gè)Local源),而后面一個(gè)名稱為Other炫掐。在模擬器中顯示的第一個(gè)日歷源的名稱只是一個(gè)便于用戶理解的別名。(但我目前還不是很清楚subscribe類型的那一項(xiàng)是什么)
然后在真機(jī)上睬涧,第一個(gè)日歷源的名字是ICLOUD募胃,第二個(gè)日歷源是“其他”旗唁。我們可以看到無論是真機(jī)還是模擬器,每個(gè)日歷源里都可以有若干個(gè)日歷痹束。
舉例獲取iCloud源:
EKSource *localSource = nil;
for (EKSource *source in _eventStore.sources){
//獲取iCloud源检疫。這里可以只通過日歷源的title來查找,不過加上對(duì)類型的檢查就是雙保險(xiǎn)
if (source.sourceType == EKSourceTypeCalDAV && [source.title isEqualToString:@"iCloud"]){
//把獲取到的iCloud源保存起來
localSource = source;
}
}
其他幾種日歷源:
typedef NS_ENUM(NSInteger, EKSourceType) {
EKSourceTypeLocal,
EKSourceTypeExchange,
EKSourceTypeCalDAV,
EKSourceTypeMobileMe,
EKSourceTypeSubscribed,
EKSourceTypeBirthdays
};
(Local是本地的源祷嘶;iCloud是遠(yuǎn)程源屎媳,網(wǎng)絡(luò)聯(lián)網(wǎng)同步數(shù)據(jù)有點(diǎn)關(guān)系,EKSourceTypeExchange也是遠(yuǎn)程源)
獲取日歷源中指定的日歷
使用EKEventStore的- (NSArray<EKCalendar *> *)calendarsForEntityType:(EKEntityType)entityType
方法论巍,這個(gè)方法會(huì)返回一個(gè)EKCalendar的數(shù)組烛谊,里面包含符合要求的日歷(支持事件的或者支持提醒的)
原本EKSource里面有一個(gè)只讀的獲取指定日歷源中所有日歷的屬性,但現(xiàn)在已經(jīng)廢棄掉了~@property(nonatomic, readonly) NSSet<EKCalendar *> *calendars NS_DEPRECATED(NA, NA, 4_0, 6_0);
EKCalendar *calendar;
for (EKCalendar *ekcalendar in [_eventStore calendarsForEntityType:EKEntityTypeEvent]) {
//當(dāng)然這里也可以加上日歷源類型的檢查嘉汰,像上面一樣的雙保險(xiǎn) calendar.type == EKCalendarTypeCalDAV
if ([ekcalendar.title isEqualToString:@"小雅"] ) {
calendar = ekcalendar;
}
}
和上面幾種日歷源對(duì)應(yīng)的日歷類型:
typedef NS_ENUM(NSInteger, EKCalendarType) {
EKCalendarTypeLocal,
EKCalendarTypeCalDAV,
EKCalendarTypeExchange,
EKCalendarTypeSubscription,
EKCalendarTypeBirthday
};
在系統(tǒng)日歷中創(chuàng)建自定義日歷
我們需要先找到iCloud大分類丹禀,然后才能創(chuàng)建自定義的日歷,而且創(chuàng)建時(shí)鞋怀,我們需要判斷是否創(chuàng)建双泪,否則,會(huì)創(chuàng)建一些具有同樣名稱的日歷
@property (nonatomic ,strong)EKCalendar *cal;
- (EKCalendar *)cal{
if (_cal == nil) {
BOOL shouldAdd = YES;
EKCalendar *calendar;
for (EKCalendar *ekcalendar in [_eventStore calendarsForEntityType:EKEntityTypeEvent]) {
if ([ekcalendar.title isEqualToString:@"小雅"] ) {
shouldAdd = NO;
calendar = ekcalendar;
}
}
if (shouldAdd) {
EKSource *localSource = nil;
//真機(jī)
for (EKSource *source in _eventStore.sources){
if (source.sourceType == EKSourceTypeCalDAV && [source.title isEqualToString:@"iCloud"]){//獲取iCloud源
localSource = source;
break;
}
}
if (localSource == nil){
//模擬器
for (EKSource *source in _eventStore.sources) {//獲取本地Local源(就是上面說的模擬器中名為的Default的日歷源)
if (source.sourceType == EKSourceTypeLocal){
localSource = source;
break;
}
}
}
calendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:_eventStore];
calendar.source = localSource;
calendar.title = @"小雅";//自定義日歷標(biāo)題
calendar.CGColor = [UIColor greenColor].CGColor;//自定義日歷顏色
NSError* error;
[_eventStore saveCalendar:calendar commit:YES error:&error];
}
_cal = calendar;
}
return _cal;
}
日歷事件查詢
要訪問日歷中的事件密似,需要提供一個(gè)查詢條件焙矛,因?yàn)橛行┲貜?fù)事件是沒有盡頭的,你不可能獲取一個(gè)無限長(zhǎng)的事件列表辛友。因此需要使用NSPredicate謂詞來進(jìn)行篩選薄扁。
- (NSPredicate *)predicateForEventsWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate calendars:(nullable NSArray<EKCalendar *> *)calendars;
在這個(gè)方法里分別需要傳入:需要查詢的開始時(shí)間剪返、截止時(shí)間废累、要查詢的日歷類型數(shù)組。返回符合條件的日歷事件(上限是四年內(nèi)脱盲,如果開始邑滨、結(jié)束的時(shí)間跨度超過4年就截取最開始的4年的事件返回)
- (NSArray*)checkEvent{
NSCalendar *calendar = [NSCalendar currentCalendar];
// 創(chuàng)建起始日期組件
NSDateComponents *oneDayAgoComponents = [[NSDateComponents alloc] init];
oneDayAgoComponents.day = -1;
NSDate *oneDayAgo = [calendar dateByAddingComponents:oneDayAgoComponents
toDate:[NSDate date]
options:0];
// 創(chuàng)建結(jié)束日期組件
NSDateComponents *oneMonthFromNowComponents = [[NSDateComponents alloc] init];
oneMonthFromNowComponents.month = 1;
NSDate *oneMonthFromNow = [calendar dateByAddingComponents:oneMonthFromNowComponents
toDate:[NSDate date]
options:0];
// 用事件庫的實(shí)例方法創(chuàng)建謂詞。表示 找出從當(dāng)前時(shí)間前一天到當(dāng)前時(shí)間的一個(gè)月后的時(shí)間范圍的所有typesArray里類型的日歷事件
NSPredicate*predicate = [self.eventStore predicateForEventsWithStartDate:oneDayAgo endDate:oneMonthFromNow calendars:@[self.cal]];
NSArray *eventArray = [self.eventStore eventsMatchingPredicate:predicate];
return eventArray;
}
這樣就獲取了從當(dāng)前時(shí)間前一天到當(dāng)前時(shí)間的一個(gè)月后的事件數(shù)組钱反。
eventArray是符合條件的日歷事件數(shù)組掖看,數(shù)組里存的是EKEvent類型數(shù)據(jù)。關(guān)于EKEvent的一些屬性和方法面哥,這里簡(jiǎn)單提幾個(gè)哎壳,詳細(xì)的看api文檔。
+ (EKEvent *)eventWithEventStore:(EKEventStore *)eventStore 創(chuàng)建一個(gè)新的自動(dòng)釋放的事件對(duì)象
@property(nonatomic, readonly) NSString *eventIdentifier; 唯一標(biāo)識(shí)符區(qū)分某個(gè)事件.修改事件有可能
@property(nonatomic, getter=isAllDay) BOOL allDay 設(shè)置是否是全天事件
@property(nonatomic, copy) NSDate *startDate; 事件開始時(shí)間
@property(nonatomic, copy) NSDate *endDate; 結(jié)束時(shí)間
@property(nonatomic, copy, nullable) EKStructuredLocation *structuredLocation 事件里添加的位置尚卫」殚牛可以獲取到經(jīng)緯度等相關(guān)信息。
- 事件修改
拿到event然后對(duì)它的各個(gè)屬性賦新值就好了吱涉。在保存時(shí)刹泄,從哪個(gè)EKEventStore里取出來就要存回哪個(gè)EKEventStore外里。
添加事件到系統(tǒng)日歷、設(shè)置重復(fù)周期特石、創(chuàng)建任意時(shí)間之前開始的提醒
添加的方法:- (BOOL)saveEvent:(EKEvent *)event span:(EKSpan)span commit:(BOOL)commit error:(NSError **)error
event:要添加的事件
span:設(shè)置跨度盅蝗。 有兩種選擇:````EKSpanThisEvent表示只影響當(dāng)前事件,
EKSpanFutureEvents表示影響當(dāng)前和以后的所有事件姆蘸。比如某條重復(fù)任務(wù)修改后保存時(shí)墩莫,傳
EKSpanThisEvent表示值修改這一條重復(fù)事件,傳
EKSpanFutureEvents```表示修改這一條和以后的所有重復(fù)事件逞敷;刪除事件時(shí)贼穆,分別表示刪除這一條;刪除這一條和以后的所有兰粉。
commit:是否馬上保存事件(類似sqlite里面的“事務(wù)”)故痊。YES表示馬上執(zhí)行,立即把此次操作提交到系統(tǒng)事件庫玖姑;NO表示此時(shí)不提交愕秫,直到調(diào)用commit:方法時(shí)才執(zhí)行。
如果一次性操作的事件數(shù)比較少的話焰络,可以每次都傳YES戴甩,實(shí)時(shí)更新事件數(shù)據(jù)庫。如果一次性操作的事件較多的話闪彼,可以每次傳NO甜孤,最后再執(zhí)行一次提交所有更改到數(shù)據(jù)庫,把原來的更改(不管是添加還是刪除)全部提交到數(shù)據(jù)庫畏腕。
error:出錯(cuò)信息缴川,如果沒出錯(cuò)值是nil。
- (void)addEventNotifyWithTitle:(NSString*)title dateString:(NSString*)dateString startSection:(NSString *)startSection endSection:(NSString *)endSection repeatIndex:(NSInteger)repeatindex alarmSettings:(NSArray *)remindIndexs note:(NSString*)notes{
//創(chuàng)建一個(gè)新事件
EKEvent *event = [EKEvent eventWithEventStore:self.eventStore];
//1.標(biāo)題
event.title = title;
//2.開始時(shí)間
event.startDate = [self.dateFormatter dateFromString:[dateString stringByAppendingString:[self sectionStartTime:startSection]]];
//3.結(jié)束時(shí)間
event.endDate = [self.dateFormatter dateFromString:[dateString stringByAppendingString:[self sectionEndTime:endSection]]];
//4.重復(fù)規(guī)則
EKRecurrenceRule *rule = [self repeatRule:repeatindex currentDate:dateString];
if (rule != nil) {
event.recurrenceRules = @[rule];
}else{
event.recurrenceRules = nil;
}
event.notes = notes;//6.備注
[event setAllDay:NO];//設(shè)置全天
//5.設(shè)置提醒
for (int i = 0; i < remindIndexs.count; i++) {
EKAlarm *alarm = [self alarmsSettingWithIndex:[remindIndexs[i] intValue]];
if (alarm == nil) {
event.alarms = nil;
break;
}
[event addAlarm:alarm];
}
[event setCalendar:self.cal];//設(shè)置日歷類型
//保存事件
NSError *err = nil;
if([self.eventStore saveEvent:event span:EKSpanThisEvent commit:NO error:nil]){//注意這里是no描馅,在外部調(diào)用完這個(gè)add方法之后一定要commit
NSLog(@"創(chuàng)建事件到系統(tǒng)日歷成功!,%@",title);
}else{
NSLog(@"創(chuàng)建失敗%@",err);
}
}
//重復(fù)規(guī)則
- (EKRecurrenceRule *)repeatRule:(NSInteger)repeatIndex currentDate:(NSString*)dateString{
NSDate *currentDate = [self.dateFormatter dateFromString:[dateString stringByAppendingString:@"0000"]];
NSCalendar * gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *components = [gregorian components:NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond fromDate:currentDate];
components.year += 1;
NSDate *recurrenceEndDate = [gregorian dateFromComponents:components];//高頻率:每天把夸、每?jī)商臁⒐ぷ魅? NSDateComponents *components2 = [gregorian components:NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond fromDate:currentDate];
components2.year += 3;
NSDate *recurrenceEndDate2 = [gregorian dateFromComponents:components2];//低頻率:每周铭污、每月恋日、每年
EKRecurrenceRule * rule;
switch (repeatIndex) {
case 0://每天
rule = [[EKRecurrenceRule alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyDaily interval:1 daysOfTheWeek:nil daysOfTheMonth:nil monthsOfTheYear:nil weeksOfTheYear:nil daysOfTheYear:nil setPositions:nil end:[EKRecurrenceEnd recurrenceEndWithEndDate:recurrenceEndDate]];
break;
case 1://每?jī)商? rule = [[EKRecurrenceRule alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyDaily interval:2 daysOfTheWeek:nil daysOfTheMonth:nil monthsOfTheYear:nil weeksOfTheYear:nil daysOfTheYear:nil setPositions:nil end:[EKRecurrenceEnd recurrenceEndWithEndDate:recurrenceEndDate]];
break;
case 2://每周
rule = [[EKRecurrenceRule alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyWeekly interval:1 daysOfTheWeek:nil daysOfTheMonth:nil monthsOfTheYear:nil weeksOfTheYear:nil daysOfTheYear:nil setPositions:nil end:[EKRecurrenceEnd recurrenceEndWithEndDate:recurrenceEndDate2]];
break;
case 3://每月
rule = [[EKRecurrenceRule alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyMonthly interval:1 daysOfTheWeek:nil daysOfTheMonth:nil monthsOfTheYear:nil weeksOfTheYear:nil daysOfTheYear:nil setPositions:nil end:[EKRecurrenceEnd recurrenceEndWithEndDate:recurrenceEndDate2]];
break;
case 4://每年
rule = [[EKRecurrenceRule alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyYearly interval:1 daysOfTheWeek:nil daysOfTheMonth:nil monthsOfTheYear:nil weeksOfTheYear:nil daysOfTheYear:nil setPositions:nil end:[EKRecurrenceEnd recurrenceEndWithEndDate:recurrenceEndDate2]];
break;
case 5://工作日
rule = [[EKRecurrenceRule alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyDaily interval:1 daysOfTheWeek:[NSArray arrayWithObjects:[EKRecurrenceDayOfWeek dayOfWeek:2],[EKRecurrenceDayOfWeek dayOfWeek:3],[EKRecurrenceDayOfWeek dayOfWeek:4],[EKRecurrenceDayOfWeek dayOfWeek:5],[EKRecurrenceDayOfWeek dayOfWeek:6],nil] daysOfTheMonth:nil monthsOfTheYear:nil weeksOfTheYear:nil daysOfTheYear:nil setPositions:nil end:[EKRecurrenceEnd recurrenceEndWithEndDate:recurrenceEndDate]];
break;
case 6:
rule = nil;
break;
default:
rule = nil;
break;
}
return rule;
}
//@[@"當(dāng)事件發(fā)生時(shí)",@"5分鐘前",@"15分鐘前",@"30分鐘前",@"1小時(shí)前",@"1天前",@"不提醒"]
- (EKAlarm *)alarmsSettingWithIndex:(int )remindIndex{
EKAlarm *alarm;
switch (remindIndex) {
case 0:
alarm = [EKAlarm alarmWithRelativeOffset:0];
break;
case 1:
alarm = [EKAlarm alarmWithRelativeOffset:- 60.0 * 5];
break;
case 2:
alarm = [EKAlarm alarmWithRelativeOffset:- 60.0 * 15];
break;
case 3:
alarm = [EKAlarm alarmWithRelativeOffset:-60.0 * 30];
break;
case 4:
alarm = [EKAlarm alarmWithRelativeOffset:-60.0 * 60];
break;
case 5:
alarm = [EKAlarm alarmWithRelativeOffset:-60.0 * 60 * 24];
break;
case 6:
alarm = nil;
break;
default:
alarm = nil;
break;
}
return alarm;
}
- 設(shè)置事件重復(fù)
主要用到EKRecurrenceRule這個(gè)類來設(shè)置重復(fù)規(guī)則
- (instancetype)initRecurrenceWithFrequency:(EKRecurrenceFrequency)type
interval:(NSInteger)interval
daysOfTheWeek:(nullable NSArray<EKRecurrenceDayOfWeek *> *)days
daysOfTheMonth:(nullable NSArray<NSNumber *> *)monthDays
monthsOfTheYear:(nullable NSArray<NSNumber *> *)months
weeksOfTheYear:(nullable NSArray<NSNumber *> *)weeksOfTheYear
daysOfTheYear:(nullable NSArray<NSNumber *> *)daysOfTheYear
setPositions:(nullable NSArray<NSNumber *> *)setPositions
end:(nullable EKRecurrenceEnd *)end;
一個(gè)個(gè)參數(shù)來看:
type:重復(fù)規(guī)則的頻率
typedef NS_ENUM(NSInteger, EKRecurrenceFrequency) {
EKRecurrenceFrequencyDaily,//按天
EKRecurrenceFrequencyWeekly,//按周
EKRecurrenceFrequencyMonthly,//按月
EKRecurrenceFrequencyYearly//按年
};
interval:間隔,必須大于0
days:一周中的哪幾天
monthDays:一個(gè)月中的哪幾號(hào)
months:一年中哪幾個(gè)月
weeksOfTheYear:一年中的哪幾周
daysOfTheYear:一年中的哪幾天
setPositions:規(guī)則外的設(shè)置
end:結(jié)束規(guī)則嘹狞。有兩種:按次數(shù)和按時(shí)間岂膳。按時(shí)間:[EKRecurrenceEnd recurrenceEndWithEndDate:recurrenceEndDate]
表示recurrenceEndDate該時(shí)間后不再計(jì)算;按次數(shù):[EKRecurrenceEnd recurrenceEndWithOccurrenceCount:10]
表示十次
舉個(gè)例子:
1.每?jī)商靾?zhí)行一次:type: EKRecurrenceFrequencyDaily磅网;interval:2
2.每工作日?qǐng)?zhí)行:type: EKRecurrenceFrequencyDaily谈截;interval:1;days為星期一...星期五,具體參數(shù)設(shè)置:[NSArray arrayWithObjects:[EKRecurrenceDayOfWeek dayOfWeek:2],[EKRecurrenceDayOfWeek dayOfWeek:3],[EKRecurrenceDayOfWeek dayOfWeek:4],[EKRecurrenceDayOfWeek dayOfWeek:5],[EKRecurrenceDayOfWeek dayOfWeek:6],nil]
3.每?jī)芍苤芤粓?zhí)行一次:type:EKRecurrenceFrequencyWeekly傻盟;interval:2速蕊;days:[NSArray arrayWithObjects:[EKRecurrenceDayOfWeek dayOfWeek:2],nil]
4.每月1號(hào)執(zhí)行一次:type: EKRecurrenceFrequencyMonthly;interval:1娘赴;monthDays:@[@1];
添加重復(fù):event.recurrenceRules = rule數(shù)組;
或者使用- (void)addRecurrenceRule:(EKRecurrenceRule *)rule;
逐個(gè)規(guī)則添加
- 創(chuàng)建任意時(shí)間之前開始的提醒
使用EKAlarm鬧鐘來做提醒功能规哲。
創(chuàng)建方法有兩種:
+ (EKAlarm *)alarmWithAbsoluteDate:(NSDate *)date; 設(shè)置絕對(duì)時(shí)間
+ (EKAlarm *)alarmWithRelativeOffset:(NSTimeInterval)offset; 設(shè)置相對(duì)時(shí)間(相對(duì)event的start date),而且這個(gè)相對(duì)時(shí)間的基本單位是秒诽表,設(shè)置負(fù)值表示事件前提醒唉锌,設(shè)置正值是事件發(fā)生后提醒
舉例:事件五分鐘前提醒
EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:- 60.0 * 5];
[event addAlarm:alarm];//逐個(gè)鬧鐘添加到事件
也可以event.alarms = 鬧鐘數(shù)組
一次性添加所有提醒。
設(shè)置了提醒后,我們打開iOS系統(tǒng)自帶的日歷App,會(huì)發(fā)現(xiàn)只會(huì)顯示2個(gè)提醒,看不到多余的提醒.但是實(shí)際測(cè)試發(fā)現(xiàn)全部提醒都可以工作,而且我們可以在Mac的日歷程序中看到所有的提醒竿奏。
刪除系統(tǒng)日歷事件
刪除的方法:- (BOOL)removeEvent:(EKEvent *)event span:(EKSpan)span commit:(BOOL)commit error:(NSError **)error
參數(shù)和添加事件方法差不多袄简,使用也很簡(jiǎn)單,這里只貼一下代碼不多敘述泛啸。
NSArray *eventArray = [self checkEventWithDateString:dateStrArray startSection:startSection endSection:endSection];
if (eventArray.count > 0) {
for (int i = 0; i < eventArray.count; i++) {
EKEvent * event = eventArray[i];
[event setCalendar:self.cal];
NSError *error = nil;
BOOL successDelete;
if (deleteFuture) {
successDelete = [self.eventStore removeEvent:event span:EKSpanFutureEvents commit:NO error:&error];
}else{
successDelete = [self.eventStore removeEvent:event span:EKSpanThisEvent commit:NO error:&error];
}
// if(!successDelete) {
// NSLog(@"刪除本條事件失敗");
// }else{
// NSLog(@"刪除本條事件成功绿语,%@",error);
// }
}
//一次提交所有操作到事件庫
[self commitEvent];
}
- (void)commitEvent{
NSError *error =nil;
BOOL commitSuccess= [self.eventStore commit:&error];
if(!commitSuccess) {
NSLog(@"一次性提交事件失敗,%@",error);
}else{
NSLog(@"成功一次性提交事件,%s",__func__);
}
}
其他
還有一個(gè)問題候址,就是在你修改事件的過程中如果事件發(fā)生了變化吕粹。
日歷發(fā)生變化時(shí)都會(huì)發(fā)出EKEventStoreChangedNotification通知,調(diào)用EKEvent的refresh方法即可刷新這個(gè)事件確保事件還是可用的岗仑,另外它還會(huì)刷新事件的屬性值匹耕,已經(jīng)修改過的屬性并不會(huì)被更新。(如果refresh方法返回NO那么這個(gè)事件已經(jīng)被刪除掉或者已經(jīng)是無效的荠雕,不應(yīng)該再使用它)稳其。
關(guān)于這個(gè)問題,因?yàn)槲疫€沒有實(shí)際使用到炸卑,所以點(diǎn)到即止既鞠。
項(xiàng)目中遇到的一個(gè)問題:如果app正在使用時(shí)切換到系統(tǒng)“設(shè)置”,把a(bǔ)pp的日歷授權(quán)關(guān)了矾兜,這時(shí)候app會(huì)崩掉损趋。不清楚原因,崩潰時(shí)斷點(diǎn)顯示“SIGKILL”