iOS常用

iOS系统日历的获取、创建、删除和修改

2021-05-19  本文已影响0人  wuyukobe
1、Info.plist 中添加获取系统日历权限提醒

Privacy - Calendars Usage Description / 有助于您更好的管理日程


权限添加
2、获取权限
/**
 EKAuthorizationStatusNotDetermined = 0,// 未进行授权选择
 EKAuthorizationStatusRestricted,//未授权,且用户无法更新,如家长控制情况下
 EKAuthorizationStatusDenied,       // 用户拒绝App使用
 EKAuthorizationStatusAuthorized,   // 已授权,可使用
 */
-(BOOL)getLocalCalendarAuthorization{
    _eventStore = [[EKEventStore alloc]init];
    EKAuthorizationStatus eventStatus = [EKEventStore  authorizationStatusForEntityType:EKEntityTypeEvent];
    __block BOOL allow = NO;
    if(eventStatus ==EKAuthorizationStatusNotDetermined){
        //用户尚未授权,提示用户授权。下边的requestAccessToEntityType:方法可以调出系统授权弹窗
        [_eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) {
            if (granted) {
                //允许
                allow = YES;
            }else{
                //不允许
                allow = NO;
            }
        }];
    }else if(eventStatus ==EKAuthorizationStatusAuthorized){
        //用户已经允许授权。作相应处理,比如查询日历里今天的所有事件..
        allow = YES;
    }
    return allow;
}
3、获取所有的系统本地日历
/// 获取系统本地日历事件
- (NSArray *)getLocalSystemCalendarEventWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate {
   NSArray * eventArray = [_eventStore calendarsForEntityType:EKEntityTypeEvent];
   NSMutableArray * onlyArray = [NSMutableArray array];
   for (int i=0; i<eventArray.count; i++) {
       EKCalendar * tempCalendar = eventArray[i];
       EKCalendarType type = tempCalendar.type;
       if (type == EKCalendarTypeCalDAV) {
           [onlyArray addObject:tempCalendar];
       }
   }
   
   NSPredicate * predicate = [_eventStore predicateForEventsWithStartDate:startDate endDate:endDate calendars:onlyArray];
   NSArray * events = [_eventStore eventsMatchingPredicate:predicate];
   return events;
}

通过 event.calendar.allowsContentModifications == YES 可以过滤节假日、节气等系统添加的日历。
由于我们手动添加的数据都是可以手动编辑的,所以event的allowsContentModifications这一只读属性刚好可以用到。

4、创建日程并写入本地日历
- (void)writeToLocalCalendarAction {
    EKEventStore *eventStore = [[EKEventStore alloc] init];

    //事件保存到日历
    //06.07 元素
    //title(标题 NSString),
    //location(位置NSString),
    //startDate(开始时间 2016/06/07 11:14AM),
    //endDate(结束时间 2016/06/07 11:14AM),
    //addAlarm(提醒时间 2016/06/07 11:14AM),
    //notes(备注类容NSString)
    
    /// 06.07 时间格式
    NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setAMSymbol:@"AM"];
    [dateFormatter setPMSymbol:@"PM"];
    [dateFormatter setDateFormat:@"hh:mm"];
    NSDate *date = [NSDate date];
    NSString * s = [dateFormatter stringFromDate:date];
    NSLog(@"%@",s);
    
    /// 创建事件
    EKEvent *event  = [EKEvent eventWithEventStore:eventStore];
    event.title  = [NSString stringWithFormat:@"写入日历事件-%@",s];
    event.location = @"北京app";
    
    /// 开始时间(必须传)
    event.startDate = [date dateByAddingTimeInterval:60 * 2];
    /// 结束时间(必须传)
    event.endDate   = [date dateByAddingTimeInterval:60 * 5 * 24];
    ///  event.allDay = YES;//全天
    
    /// 添加提醒
    /// 第一次提醒  (几分钟后)
    [event addAlarm:[EKAlarm alarmWithRelativeOffset:60.0f * -1.0f]];
    /// 第二次提醒  ()
    /// [event addAlarm:[EKAlarm alarmWithRelativeOffset:60.0f * -10.0f * 24]];
    
    /// 06.07 add 事件类容备注
    NSString * str = @"这是备注";
    event.notes = [NSString stringWithFormat:@"%@:%@",str,s];
    /// 将日历事件添加到默认的日历源中
    [event setCalendar:[eventStore defaultCalendarForNewEvents]];
    /// 保存日历事件
    NSError *err;
    [eventStore saveEvent:event span:EKSpanThisEvent error:&err];
}
5、删除单个日历和删除所有日历
/// 删除日历事件(删除单个)
/// @param eventIdentifier 事件ID(标识符)
- (BOOL)deleteCalendarEventIdentifier:(NSString *)eventIdentifier{
    EKEvent *event;
    NSError*error =nil;
    if (eventIdentifier && ![eventIdentifier isEqualToString:@""]) {
        event = [self.eventStore eventWithIdentifier:eventIdentifier];
        /// commit:NO:最后再一次性提交,YES:当前提交
        return [self.eventStore removeEvent:event span:EKSpanThisEvent commit:YES error:&error];
//        一次提交所有操作到事件库
//        NSError *errored = nil;
//        BOOL commitSuccess = [self.eventStore commit:&errored];
//        return commitSuccess;
    }
    return NO;
}

/// 删除日历事件(可删除一段时间内的事件)
/// @param startDate 开始时间
/// @param endDate 结束时间
- (BOOL)deleteCalendarStartDate:(NSDate *)startDate addEndDate:(NSDate *)endDate {
    // 获取到此事件
    NSArray * eventArray = [self.eventStore calendarsForEntityType:EKEntityTypeEvent];
    NSMutableArray * onlyArray = [NSMutableArray array];
    for (int i=0; i<eventArray.count; i++) {
        EKCalendar * tempCalendar = eventArray[i];
        EKCalendarType type = tempCalendar.type;
        if (type == EKCalendarTypeCalDAV) {
            [onlyArray addObject:tempCalendar];
        }
    }
    
    NSPredicate * predicate = [self.eventStore predicateForEventsWithStartDate:startDate endDate:endDate calendars:onlyArray];
    NSArray * events = [self.eventStore eventsMatchingPredicate:predicate];
    
    for (int i = 0; i < events.count; i ++) {
        // 删除这一条事件
        EKEvent *event = events[i];
        NSError*error =nil;
        
        // commit:NO:最后再一次性提交
        [self.eventStore removeEvent:event span:EKSpanThisEvent commit:NO error:&error];
    }
    //一次提交所有操作到事件库
    NSError *errored = nil;
    BOOL commitSuccess = [self.eventStore commit:&errored];
    return commitSuccess;
}

- (EKEventStore *)eventStore {
    if (!_eventStore) {
        _eventStore = [[EKEventStore alloc]init];
    }
    return _eventStore;
}
6、修改日历:

根据eventIdentifier 查找对应日历,没找到则重新创建,找如果有先删除在重新创建。

7、问题解决:

(1)唯一事件id(eventIdentifier)只读的问题:事件创建之后,系统自动创建eventIdentifier,而我们无法准确找到对应事件的 eventIdentifier。

@property(null_unspecified, nonatomic, readonly) NSString *eventIdentifier;

(2)获取本地日历中的日程数据数据量可能会很大,导致与服务端返回的新数据进行匹配的时候双重for循环影响效率。
解决方案:使用allowsContentModifications属性。由于我们手动添加的数据都是可以手动编辑的,所以event的allowsContentModifications这一只读属性刚好可以用到。可以减少很多系统日历自带的event对象,比如节假日、节气等等。

event.calendar.allowsContentModifications == YES
8、其他

(1)基于地理位置的提醒
我们可以设定当用户进入或离开指定的地理位置区域时,触发日程提醒。例如当用户离开公司,提醒用户需要到超市购买日用品,作为开发者,需要确定一个经纬度以及一个半径范围。

EKAlarm *alarm = [[EKAlarm alloc] init];
    EKStructuredLocation *location = [EKStructuredLocation
                                      locationWithTitle:@"Current Location"];
location.geoLocation = [[CLLocation alloc] initWithLatitude:23.1754700000 longitude:113.4147400000];
alarm.structuredLocation = location;
alarm.proximity = EKAlarmProximityEnter;
[event addAlarm:alarm];

参考:

1、iOS 添加项目到系统日历
2、iOS增、删、改、查系统提醒事件和日历事件
3、iOS—EventKit实现app日程同步到本地日历(唯一id,过滤节假日)

上一篇下一篇

猜你喜欢

热点阅读