iOS EventKit日歷事件操作 開發(fā)筆記

最近手頭上一個(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”

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末椅寺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蒋失,更是在濱河造成了極大的恐慌返帕,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件篙挽,死亡現(xiàn)場(chǎng)離奇詭異荆萤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門链韭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來偏竟,“玉大人,你說我怎么就攤上這事敞峭∮荒保” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵旋讹,是天一觀的道長(zhǎng)殖蚕。 經(jīng)常有香客問我,道長(zhǎng)沉迹,這世上最難降的妖魔是什么睦疫? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮鞭呕,結(jié)果婚禮上蛤育,老公的妹妹穿的比我還像新娘。我一直安慰自己葫松,他們只是感情好缨伊,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著进宝,像睡著了一般刻坊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上党晋,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天谭胚,我揣著相機(jī)與錄音,去河邊找鬼未玻。 笑死灾而,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扳剿。 我是一名探鬼主播旁趟,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼庇绽!你這毒婦竟也來了锡搜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤瞧掺,失蹤者是張志新(化名)和其女友劉穎耕餐,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辟狈,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肠缔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年夏跷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片明未。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡槽华,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出趟妥,到底是詐尸還是另有隱情猫态,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布煮纵,位于F島的核電站懂鸵,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏行疏。R本人自食惡果不足惜匆光,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酿联。 院中可真熱鬧终息,春花似錦、人聲如沸贞让。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喳张。三九已至续镇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間销部,已是汗流浹背摸航。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留舅桩,地道東北人酱虎。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像擂涛,于是被迫代替她去往敵國和親读串。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容