IOS 往手機日曆裡增,刪,查,該事件提醒
阿新 • • 發佈:2018-12-17
之前對這個塊也不是很熟悉,然後在一個專案上使用過,所以這裡就記下筆記,僅供參考。
準備工作
1.需要在工程中引入EventKit框架,#import <EventKit/EventKit.h>
2.引入了此框架後,我們可以用來作業系統日曆和提醒事項,這兩個app都是IOS系統自帶的功能。
3.這裡有個EKEventStore,相當於一個數據庫身份。因為使用比較頻繁,建議建立成單例模式。
4.新增日曆訪問許可權,IOS10之後需要往info.plist裡面配置日曆訪問許可權(NSCalendarsUsageDescription)
日曆許可權檢測
//日曆許可權檢測 - (void)checkCalendarAuthorizationCompletion:(void(^)(BOOL granted, NSError *error))completion { //EKEventStore //檢查日曆授權狀態 /* EKAuthorizationStatusNotDetermined = 0, //未進行授權選擇 EKAuthorizationStatusRestricted, //未授權,且使用者無法更新,如家長控制情況下 EKAuthorizationStatusDenied, //使用者拒絕App使用 EKAuthorizationStatusAuthorized, //已授權,可使用 */ EKAuthorizationStatus authorizationStatus = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent]; if (authorizationStatus == EKAuthorizationStatusNotDetermined || authorizationStatus == EKAuthorizationStatusDenied) { //未進行授權選擇 [[self sharedEKEventStore] requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) { if (granted) { DLog(@"授權成功"); if (completion) { completion(true,nil); } }else{ DLog(@"授權失敗,error:%@",error); if (completion) { completion(false,error); } } }]; }else if (EKAuthorizationStatusRestricted == authorizationStatus){ if (completion) { completion(false,nil); } }else if (EKAuthorizationStatusAuthorized == authorizationStatus){ if (completion) { completion(true,nil); } } }
新增日曆事件
//新增日曆事件 - (void)addCalendarStartDate:(NSString *)startDate addEndDate:(NSString *)endDate alarms:(NSArray *)alarmArray title:(NSString *)title { EKEvent *event = [EKEvent eventWithEventStore:[self sharedEKEventStore]]; event.title = title; event.startDate = [NSDate dateWithString:startDate formatString:@"YYYY-MM-dd HH:mm:ss"]; event.endDate = [NSDate dateWithString:endDate formatString:@"YYYY-MM-dd HH:mm:ss"]; // 是否設定全天 event.allDay = NO; //新增提醒 if (alarmArray && alarmArray.count > 0){ for (NSNumber *timeValue in alarmArray) { //如果需要設定提前提醒,需要設定一個負數時間值,單位秒s,根據實際需求轉換單位 [event addAlarm:[EKAlarm alarmWithRelativeOffset:-1*[timeValue integerValue]*60]]; } } //獲取日曆型別 EKCalendar *calendar = [self findEKCalendar:@"根據實際需求新建一個名稱即可" eventStore:[self sharedEKEventStore]]; [event setCalendar:calendar]; // 儲存日曆 NSError *errSave; //EKSpanThisEvent 表示單次日曆事件 如果需要儲存重複事件需要使用EKSpanFutureEvents //commit 表示當前修改是否要立即提交,因為頻繁操作資料庫,建議先儲存需要新增的事件,最後一把全部提交 [[self sharedEKEventStore] saveEvent:event span:EKSpanThisEvent commit:NO error:&errSave]; if (errSave) { DLog(@"儲存失敗,%@",errSave); }else{ DLog(@"儲存成功"); } }
刪除日曆事件
// 刪除日曆事件
- (BOOL)deleteCalendarStartDate:(NSString *)startDate addEndDate:(NSString *)endDate addModifytitle:(NSString *)modifytitle{
// 獲取到此事件
NSArray *request = [self checkToStartDate:startDate addEndDate:endDate addModifytitle:modifytitle];
for (int i = 0; i < request.count; i ++) {
// 刪除這一條事件
EKEvent *event = request[i];
//獲取日曆型別
EKCalendar *calendar = [self findEKCalendar:@"根據實際需求新建一個名稱即可" eventStore:[self sharedEKEventStore]];
[event setCalendar:calendar];
NSError*error =nil;
// commit:NO:最後再一次性提交
[[self sharedEKEventStore] removeEvent:event span:EKSpanThisEvent commit:NO error:&error];
}
//一次提交所有操作到事件庫
NSError *errored = nil;
BOOL commitSuccess= [[self sharedEKEventStore] commit:&errored];
if (errored) {
DLog(@"刪除失敗,%@",errored);
}else{
DLog(@"刪除成功");
}
return commitSuccess;
}
查詢日曆事件
//查詢日曆中是否有相同的日曆事件
- (NSArray *)checkToStartDate:(NSString *)startDate addEndDate:(NSString *)endDate addModifytitle:modifytitle
{
//查詢所有的日曆
NSArray *tempArray = [[self sharedEKEventStore] calendarsForEntityType:EKEntityTypeEvent];
NSMutableArray *only3D = [NSMutableArray array];
for (int i=0; i<tempArray.count; i++) {
EKCalendar *temCalendar = tempArray[i];
EKCalendarType type = temCalendar.type;
// 工作、家庭和本地日曆
if (type == EKCalendarTypeLocal || type == EKCalendarTypeCalDAV) {
[only3D addObject:temCalendar];
}
}
//謂詞查詢所有符合條件的日曆事件,開始時間-結束時間之內的所有
NSPredicate *predicate = [[self sharedEKEventStore] predicateForEventsWithStartDate:[NSDate dateWithString:startDate formatString:@"YYYY-MM-dd HH:mm:ss"] endDate:[NSDate dateWithString:endDate formatString:@"YYYY-MM-dd HH:mm:ss"] calendars:only3D];
// 獲取到範圍內的所有事件
NSArray *request = [[self sharedEKEventStore] eventsMatchingPredicate:predicate];
request = [request sortedArrayUsingSelector:@selector(compareStartDateWithEvent:)];
if (!modifytitle || [modifytitle isEqualToString:@""]) {
return request;
}else{
//日曆事件標題篩選
NSMutableArray *onlyRequest = [NSMutableArray array];
for (int i = 0; i < request.count; i++) {
EKEvent *event = request[i];
if (event.title && [event.title isEqualToString:modifytitle]) {
[onlyRequest addObject:event];
}
}
return onlyRequest;
}
}
修改日曆事件
這裡並沒有直接修改日曆的介面,所以我們需要變向的達到要求。先做一下刪除操作,然後再新增。
- (BOOL)updateCalendarStartDate:(NSString *)startDate addEndDate:(NSString *)endDate addModifytitle:(NSString *)modifytitle
{
//1.檢測是否有相同的日曆事件
NSArray *searchResult = [self checkToStartDate:scheduled.startTime addEndDate:scheduled.endTime addModifytitle:scheduled.title];
//2.判斷該日曆事件是否為新增/修改,還是直接刪除
if (searchResult.count>0) {
//1.刪除相同日曆事件
[self deleteCalendarStartDate:scheduled.startTime addEndDate:scheduled.endTime addModifytitle:scheduled.title];
//2.新增日曆事件
[self addCalendarStartDate:scheduled.startTime addEndDate:scheduled.endTime alarms:@[@(scheduled.scheduleNoticeTime)] title:scheduled.title];
}else{
//沒有相同日曆事件,新增日曆事件
[self addCalendarStartDate:scheduled.startTime addEndDate:scheduled.endTime alarms:@[@(scheduled.scheduleNoticeTime)] title:scheduled.title];
}
return YES;
}
完整的寫入操作
- (EKEventStore *)sharedEKEventStore
{
static EKEventStore *eventStore = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
eventStore = [[EKEventStore alloc] init];
});
return eventStore;
}
- (void)writeScheduledProjectToCalendar:(NSArray <ZDHCScheduledModel*>*)scheduledList
{
[self checkCalendarAuthorizationCompletion:^(BOOL granted, NSError *error) {
if (granted) {
//建立日曆
EKCalendar *ekCalendar = [self findEKCalendar:@"根據實際需求新建一個名稱" eventStore:[self sharedEKEventStore]];
if (!ekCalendar) {
NSError *err3 = nil;
ekCalendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:[self sharedEKEventStore]];
ekCalendar.title = @"根據實際需求新建一個名稱";
ekCalendar.source = [self findEKSourceWitheventStore:[self sharedEKEventStore]];
[[self sharedEKEventStore] saveCalendar:ekCalendar commit:YES error:&err3];
if (err3) {
DLog(@"建立日曆失敗");
}else{
DLog(@"建立日曆成功");
}
}
[scheduledList enumerateObjectsUsingBlock:^(ZDHCScheduledModel * _Nonnull scheduled, NSUInteger idx, BOOL * _Nonnull stop) {
//1.檢測是否有相同的日曆事件
NSArray *searchResult = [self checkToStartDate:scheduled.startTime addEndDate:scheduled.endTime addModifytitle:scheduled.title];
//2.判斷該日曆事件是否為新增/修改,還是直接刪除
if (scheduled.status) {
if (searchResult.count>0) {
//1.刪除相同日曆事件
[self deleteCalendarStartDate:scheduled.startTime addEndDate:scheduled.endTime addModifytitle:scheduled.title];
//2.新增日曆事件
[self addCalendarStartDate:scheduled.startTime addEndDate:scheduled.endTime alarms:@[@(scheduled.scheduleNoticeTime)] title:scheduled.title];
}else{
//沒有相同日曆事件,新增日曆事件
[self addCalendarStartDate:scheduled.startTime addEndDate:scheduled.endTime alarms:@[@(scheduled.scheduleNoticeTime)] title:scheduled.title];
}
}else{
if (searchResult.count>0) {
//直接刪除
[self deleteCalendarStartDate:scheduled.startTime addEndDate:scheduled.endTime addModifytitle:scheduled.title];
}
}
}];
//最後一把全部提交修改
NSError *allUpdateCommitErr;
[[self sharedEKEventStore] commit:&allUpdateCommitErr];
if (allUpdateCommitErr) {
DLog(@"提交完畢報錯,:%@",allUpdateCommitErr);
}else{
DLog(@"提交成功");
}
}
}];
}
- (EKCalendar*) findEKCalendar:(NSString *)calendarName eventStore: (EKEventStore*)eventStore{
NSArray<EKCalendar *> *calendars = [eventStore calendarsForEntityType:EKEntityTypeEvent];
if (calendars != nil && calendars.count > 0) {
for (EKCalendar *thisCalendar in calendars) {
DLog(@"Calendar: %@", thisCalendar.title);
if ([thisCalendar.title isEqualToString:calendarName]) {
return thisCalendar;
}
if ([thisCalendar.calendarIdentifier isEqualToString:calendarName]) {
return thisCalendar;
}
}
}
DLog(@"No match found for calendar with name: %@", calendarName);
return nil;
}
- (EKSource*) findEKSourceWitheventStore: (EKEventStore*) eventStore{
// if iCloud is on, it hides the local calendars, so check for iCloud first
for (EKSource *source in eventStore.sources) {
if (source.sourceType == EKSourceTypeCalDAV && [source.title isEqualToString:@"iCloud"]) {
return source;
}
}
// ok, not found.. so it's a local calendar
for (EKSource *source in eventStore.sources) {
if (source.sourceType == EKSourceTypeLocal) {
return source;
}
}
return nil;
}
到此完美結束。