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

最近手頭上一個日程管理的項目里有一個功能是做事務(wù)提醒的,原本是想用本地推送來實現(xiàn),但是無奈本地推送數(shù)量有限制,最多不能超過64條。如果改用遠程推送來實現(xiàn),那是最好的了,但是資源、條件不是很完備(畢竟是學(xué)生項目,要申請開發(fā)者賬號還得增加后臺同學(xué)工作量等等),最后選擇了用系統(tǒng)日歷來完成。在此做了一些總結(jié),方便日后查閱。

了解EventKit框架

事件庫框架授權(quán)訪問用戶的 Calendar.app 和 Reminders.app 應(yīng)用的信息。盡管是用兩個不同的應(yīng)用顯示用戶的日歷和提醒數(shù)據(jù),但確是同一個框架維護這份數(shù)據(jù)。他們使用相同的庫(EKEventStore)處理數(shù)據(jù)。

該框架除了允許檢索用戶已經(jīng)存在的calendar和reminder數(shù)據(jù)外,還允許創(chuàng)建新的事件和提醒。更高級的任務(wù),諸如添加鬧鐘或指定循環(huán)事件,也可以使用事件庫完成。

使用

準備

在項目中導(dǎo)入EventKit框架和EventKitUI框架



在使用到這個框架的文件中import進來:

#import <EventKit/EventKit.h>
#import <EventKitUI/EventKitUI.h>

創(chuàng)建一個事件庫實例

EKEventStore *eventStore = [[EKEventStore alloc] init];
因為EKEventStore就像數(shù)據(jù)庫一樣,頻繁的開啟,關(guān)閉會影響效率,所以如果你的程序需要頻繁操作日歷和提醒,建議僅生成該對象一次,僅用一個對象進行操作。因此項目里面我單獨寫了一個類封裝對日歷的操作,并用單例創(chuàng)建EKEventStore實例。

授權(quán)

iOS10以后獲得授權(quán)要在plist文件中進行設(shè)置:添加權(quán)限字符串訪問日歷:NSCalendarsUsageDescription 訪問提醒事項:NSRemindersUsageDescription


EKEntityType有兩類

EKEntityTypeEvent日歷事件 ,   EKEntityTypeReminder//提醒事項
- (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)用使用日歷,請到 設(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),且用戶無法更新,如家長控制情況下

檢查授權(quán)狀態(tài)我們使用的是EKEventStore authorizationStatusForEntityType:類方法,而調(diào)出系統(tǒng)日歷事件授權(quán)彈窗使用的卻是EKEventStore的實例方法requestAccessToEntityType:

找到對應(yīng)的日歷源

日歷源它是EKSource的實例對象,可以理解為是按照日歷類型去分類的一些組。在模擬器下:


模擬器截圖

在這個圖里,我們看到有兩個日歷源,一個是“ON MY IPHONE”另一個是"OTHER"。這里我們打個斷點查看所有日歷源:



可以看到日歷數(shù)據(jù)庫中第一個日歷源的真正名稱為Default(是一個Local源),而后面一個名稱為Other。在模擬器中顯示的第一個日歷源的名稱只是一個便于用戶理解的別名。(但我目前還不是很清楚subscribe類型的那一項是什么)

然后在真機上,第一個日歷源的名字是ICLOUD,第二個日歷源是“其他”。我們可以看到無論是真機還是模擬器,每個日歷源里都可以有若干個日歷。

舉例獲取iCloud源:

EKSource *localSource = nil;
for (EKSource *source in _eventStore.sources){
//獲取iCloud源。這里可以只通過日歷源的title來查找,不過加上對類型的檢查就是雙保險
   if (source.sourceType == EKSourceTypeCalDAV && [source.title isEqualToString:@"iCloud"]){
    //把獲取到的iCloud源保存起來
    localSource = source;
   }
}

其他幾種日歷源:

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

(Local是本地的源;iCloud是遠程源,網(wǎng)絡(luò)聯(lián)網(wǎng)同步數(shù)據(jù)有點關(guān)系,EKSourceTypeExchange也是遠程源)

獲取日歷源中指定的日歷

使用EKEventStore的- (NSArray<EKCalendar *> *)calendarsForEntityType:(EKEntityType)entityType方法,這個方法會返回一個EKCalendar的數(shù)組,里面包含符合要求的日歷(支持事件的或者支持提醒的)
原本EKSource里面有一個只讀的獲取指定日歷源中所有日歷的屬性,但現(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)然這里也可以加上日歷源類型的檢查,像上面一樣的雙保險 calendar.type == EKCalendarTypeCalDAV
      if ([ekcalendar.title isEqualToString:@"小雅"] ) {
           calendar = ekcalendar;
      }
}

和上面幾種日歷源對應(yīng)的日歷類型:

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

在系統(tǒng)日歷中創(chuàng)建自定義日歷


我們需要先找到iCloud大分類,然后才能創(chuàng)建自定義的日歷,而且創(chuàng)建時,我們需要判斷是否創(chuàng)建,否則,會創(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;
            //真機
            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 = @"小雅";//自定義日歷標題
            calendar.CGColor = [UIColor greenColor].CGColor;//自定義日歷顏色
            NSError* error;
            [_eventStore saveCalendar:calendar commit:YES error:&error];
        }
        _cal = calendar;
    }
    return _cal;
}

日歷事件查詢

要訪問日歷中的事件,需要提供一個查詢條件,因為有些重復(fù)事件是沒有盡頭的,你不可能獲取一個無限長的事件列表。因此需要使用NSPredicate謂詞來進行篩選。
- (NSPredicate *)predicateForEventsWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate calendars:(nullable NSArray<EKCalendar *> *)calendars;在這個方法里分別需要傳入:需要查詢的開始時間、截止時間、要查詢的日歷類型數(shù)組。返回符合條件的日歷事件(上限是四年內(nèi),如果開始、結(jié)束的時間跨度超過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];
    // 用事件庫的實例方法創(chuàng)建謂詞。表示 找出從當(dāng)前時間前一天到當(dāng)前時間的一個月后的時間范圍的所有typesArray里類型的日歷事件
    NSPredicate*predicate = [self.eventStore predicateForEventsWithStartDate:oneDayAgo endDate:oneMonthFromNow calendars:@[self.cal]];
    NSArray *eventArray = [self.eventStore eventsMatchingPredicate:predicate];
    return eventArray;
}

這樣就獲取了從當(dāng)前時間前一天到當(dāng)前時間的一個月后的事件數(shù)組。

eventArray是符合條件的日歷事件數(shù)組,數(shù)組里存的是EKEvent類型數(shù)據(jù)。關(guān)于EKEvent的一些屬性和方法,這里簡單提幾個,詳細的看api文檔。

+ (EKEvent *)eventWithEventStore:(EKEventStore *)eventStore 創(chuàng)建一個新的自動釋放的事件對象
@property(nonatomic, readonly) NSString *eventIdentifier; 唯一標識符區(qū)分某個事件.修改事件有可能
@property(nonatomic, getter=isAllDay) BOOL allDay 設(shè)置是否是全天事件
@property(nonatomic, copy) NSDate *startDate; 事件開始時間
@property(nonatomic, copy) NSDate *endDate; 結(jié)束時間
@property(nonatomic, copy, nullable) EKStructuredLocation *structuredLocation 事件里添加的位置??梢垣@取到經(jīng)緯度等相關(guān)信息。
  • 事件修改
    拿到event然后對它的各個屬性賦新值就好了。在保存時,從哪個EKEventStore里取出來就要存回哪個EKEventStore。

添加事件到系統(tǒng)日歷、設(shè)置重復(fù)周期、創(chuàng)建任意時間之前開始的提醒

添加的方法:- (BOOL)saveEvent:(EKEvent *)event span:(EKSpan)span commit:(BOOL)commit error:(NSError **)error
event:要添加的事件
span:設(shè)置跨度。 有兩種選擇:````EKSpanThisEvent表示只影響當(dāng)前事件,EKSpanFutureEvents表示影響當(dāng)前和以后的所有事件。比如某條重復(fù)任務(wù)修改后保存時,傳EKSpanThisEvent表示值修改這一條重復(fù)事件,傳EKSpanFutureEvents```表示修改這一條和以后的所有重復(fù)事件;刪除事件時,分別表示刪除這一條;刪除這一條和以后的所有。
commit:是否馬上保存事件(類似sqlite里面的“事務(wù)”)。YES表示馬上執(zhí)行,立即把此次操作提交到系統(tǒng)事件庫;NO表示此時不提交,直到調(diào)用commit:方法時才執(zhí)行。
如果一次性操作的事件數(shù)比較少的話,可以每次都傳YES,實時更新事件數(shù)據(jù)庫。如果一次性操作的事件較多的話,可以每次傳NO,最后再執(zhí)行一次提交所有更改到數(shù)據(jù)庫,把原來的更改(不管是添加還是刪除)全部提交到數(shù)據(jù)庫。
error:出錯信息,如果沒出錯值是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)建一個新事件
    EKEvent *event = [EKEvent eventWithEventStore:self.eventStore];
    //1.標題
    event.title = title;
    //2.開始時間
    event.startDate = [self.dateFormatter dateFromString:[dateString stringByAppendingString:[self sectionStartTime:startSection]]];
    //3.結(jié)束時間
    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)用完這個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];//高頻率:每天、每兩天、工作日
    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://每兩天
            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ā)生時",@"5分鐘前",@"15分鐘前",@"30分鐘前",@"1小時前",@"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這個類來設(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;

一個個參數(shù)來看:
type:重復(fù)規(guī)則的頻率

typedef NS_ENUM(NSInteger, EKRecurrenceFrequency) {
    EKRecurrenceFrequencyDaily,//按天
    EKRecurrenceFrequencyWeekly,//按周
    EKRecurrenceFrequencyMonthly,//按月
    EKRecurrenceFrequencyYearly//按年
};

interval:間隔,必須大于0
days:一周中的哪幾天
monthDays:一個月中的哪幾號
months:一年中哪幾個月
weeksOfTheYear:一年中的哪幾周
daysOfTheYear:一年中的哪幾天
setPositions:規(guī)則外的設(shè)置
end:結(jié)束規(guī)則。有兩種:按次數(shù)和按時間。按時間:[EKRecurrenceEnd recurrenceEndWithEndDate:recurrenceEndDate]表示recurrenceEndDate該時間后不再計算;按次數(shù):[EKRecurrenceEnd recurrenceEndWithOccurrenceCount:10]表示十次

舉個例子:
1.每兩天執(zhí)行一次:type: EKRecurrenceFrequencyDaily;interval:2
2.每工作日執(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.每兩周周一執(zhí)行一次:type:EKRecurrenceFrequencyWeekly;interval:2;days:[NSArray arrayWithObjects:[EKRecurrenceDayOfWeek dayOfWeek:2],nil]
4.每月1號執(zhí)行一次:type: EKRecurrenceFrequencyMonthly;interval:1;monthDays:@[@1];

添加重復(fù):event.recurrenceRules = rule數(shù)組;或者使用- (void)addRecurrenceRule:(EKRecurrenceRule *)rule;逐個規(guī)則添加

  • 創(chuàng)建任意時間之前開始的提醒
    使用EKAlarm鬧鐘來做提醒功能。
    創(chuàng)建方法有兩種:
 + (EKAlarm *)alarmWithAbsoluteDate:(NSDate *)date; 設(shè)置絕對時間
 + (EKAlarm *)alarmWithRelativeOffset:(NSTimeInterval)offset; 設(shè)置相對時間(相對event的start date),而且這個相對時間的基本單位是秒,設(shè)置負值表示事件前提醒,設(shè)置正值是事件發(fā)生后提醒

舉例:事件五分鐘前提醒

EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:- 60.0 * 5];
[event addAlarm:alarm];//逐個鬧鐘添加到事件

也可以event.alarms = 鬧鐘數(shù)組一次性添加所有提醒。

設(shè)置了提醒后,我們打開iOS系統(tǒng)自帶的日歷App,會發(fā)現(xiàn)只會顯示2個提醒,看不到多余的提醒.但是實際測試發(fā)現(xiàn)全部提醒都可以工作,而且我們可以在Mac的日歷程序中看到所有的提醒。

刪除系統(tǒng)日歷事件

刪除的方法:- (BOOL)removeEvent:(EKEvent *)event span:(EKSpan)span commit:(BOOL)commit error:(NSError **)error參數(shù)和添加事件方法差不多,使用也很簡單,這里只貼一下代碼不多敘述。

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__);
    }
}

其他

還有一個問題,就是在你修改事件的過程中如果事件發(fā)生了變化。
日歷發(fā)生變化時都會發(fā)出EKEventStoreChangedNotification通知,調(diào)用EKEvent的refresh方法即可刷新這個事件確保事件還是可用的,另外它還會刷新事件的屬性值,已經(jīng)修改過的屬性并不會被更新。(如果refresh方法返回NO那么這個事件已經(jīng)被刪除掉或者已經(jīng)是無效的,不應(yīng)該再使用它)。
關(guān)于這個問題,因為我還沒有實際使用到,所以點到即止。

項目中遇到的一個問題:如果app正在使用時切換到系統(tǒng)“設(shè)置”,把app的日歷授權(quán)關(guān)了,這時候app會崩掉。不清楚原因,崩潰時斷點顯示“SIGKILL”

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容