一、关于系统日历和提醒事宜

iOS系统自带的Calendar应用非常强大,用户可以在其中添加日程事件,并且其提供了接口供其他应用进行调用,可以向日历中进行事件的读取和写入。

首先,Canlendar应用默认创建了几个类型的日历,用户也可以根据需要创建自定义的日历,如下图:

在上图中,US Holidays、Birthdays、Siri Found in Apps和Calendar是默认创建的几个日历,Custom是自定义的日历,当用户新建日历事件时,需要关联到某个日历,如下:

对于系统的Reminders,其主要作用是提供事件列表,用户可以向事件列表中添加提醒事件,同样,提供默认创建了两个事件列表,用户也可以根据需要自行创建新的事件列表,如下图:

使用日历和提醒事宜这两个应用,可以提高生活工作效率,例如邮件应用通过与日历的交互可以将会议邮件添加到用户的日程中,EventKit框架则是提供了接口与这两个应用进行交互。

二、EventKit框架概览

EventKit核心的用途是配合系统的日历与提醒应用,对事件提醒进行管理,其中核心类即结构如下:

从图中可以看出,重要数据的管理类为EKEventStore,其他类都是用来描述对应的数据,下面会一一介绍。

三、日历事件操作

第三方应用需要操作用户的日历事件,需要获取用户授权,首先需要在info.plist文件中添加如下权限请求字段:

获取当前Calendars应用中定义的日历示例代码如下:

#import "ViewController.h"
#import <EventKit/EventKit.h>@interface ViewController ()
@property (nonatomic, strong) EKEventStore *eventStore;
@end@implementation ViewController
- (void)viewDidLoad {[super viewDidLoad];// 初始化self.eventStore = [[EKEventStore alloc] init];// 请求权限[self.eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) {if (!granted) {NSLog(@"拒绝访问");} else {// 获取所有日历NSArray *calendars = [self.eventStore calendarsForEntityType:EKEntityTypeEvent];for (EKCalendar *calendar in calendars) {NSLog(@"%@", calendar);}}}];
}
@end

上面方法会获取到所有的日历,也可以通过来源来获取日历,后面会具体介绍。

使用如下代码可以添加新的日历,通常,第三方应用如果要向用户日历中添加事件,可以先添加一个新的日历:

- (void)createNewCalendar {EKCalendar *calendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:self.eventStore];for (EKSource *source in self.eventStore.sources) {if (source.sourceType == EKSourceTypeLocal) {// 设置来源为本地calendar.source = source;}}calendar.title = @"珲少的事项日历";//自定义日历标题calendar.CGColor = [UIColor purpleColor].CGColor;//自定义日历颜色NSError* error;[_eventStore saveCalendar:calendar commit:YES error:&error];
}

效果如下图:

日历事件的查询需要构造NSPredicate对象,示例如下:

- (void)queryEvent {for (EKCalendar *cal in [self.eventStore calendarsForEntityType:EKEntityTypeEvent]) {if ([cal.title isEqualToString:@"珲少的事项日历"]) {NSCalendar *calendar = [NSCalendar currentCalendar];NSDateComponents *oneMonthFromNowComponents = [[NSDateComponents alloc] init];oneMonthFromNowComponents.month = 1;NSDate *oneMonthFromNow = [calendar dateByAddingComponents:oneMonthFromNowComponentstoDate:[NSDate date]options:0];// 获取从今往后一个月的NSPredicate*predicate = [self.eventStore predicateForEventsWithStartDate:[NSDate date] endDate:oneMonthFromNow calendars:@[cal]];NSArray *eventArray = [self.eventStore eventsMatchingPredicate:predicate];NSLog(@"%@", eventArray);}}
}

通过存储的相关接口,也可以对某个事件进行修改,或创建新的事件,示例如下:

- (void)createEvent {EKCalendar *calen = nil;for (EKCalendar *cal in [self.eventStore calendarsForEntityType:EKEntityTypeEvent]) {if ([cal.title isEqualToString:@"珲少的事项日历"]) {calen = cal;}}EKEvent *event = [EKEvent eventWithEventStore:self.eventStore];event.title = @"从应用创建的事件";event.startDate = [NSDate date];event.calendar = calen;NSCalendar *calendar = [NSCalendar currentCalendar];NSDateComponents *oneMonthFromNowComponents = [[NSDateComponents alloc] init];oneMonthFromNowComponents.hour += 1;NSDate *endDate = [calendar dateByAddingComponents:oneMonthFromNowComponentstoDate:[NSDate date]options:0];event.endDate = endDate;event.notes = @"备注";[event setAllDay:NO];//设置全天//保存事件NSError *error = nil;[self.eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&error];NSLog(@"%@",error);
}

下面示例代码用来删除日历事件:

- (void)removeEvent {for (EKCalendar *cal in [self.eventStore calendarsForEntityType:EKEntityTypeEvent]) {if ([cal.title isEqualToString:@"珲少的事项日历"]) {NSCalendar *calendar = [NSCalendar currentCalendar];NSDateComponents *oneMonthFromNowComponents = [[NSDateComponents alloc] init];oneMonthFromNowComponents.month = 1;NSDate *oneMonthFromNow = [calendar dateByAddingComponents:oneMonthFromNowComponentstoDate:[NSDate date]options:0];// 获取从今往后一个月的NSPredicate*predicate = [self.eventStore predicateForEventsWithStartDate:[NSDate date] endDate:oneMonthFromNow calendars:@[cal]];NSArray *eventArray = [self.eventStore eventsMatchingPredicate:predicate];[self.eventStore removeEvent:eventArray.firstObject span:EKSpanThisEvent error:nil];}}
}

三、提醒事件

提醒事件的用法和日历事件的用法基本一致,首先在Reminder应用中,每一个列表就是一个日历,下面代码示例了向列表中插入提醒事件的方法:

- (void)createNewReminder {EKReminder *reminder = [EKReminder reminderWithEventStore:self.eventStore];reminder.title = @"从应用创建的事件";reminder.notes = @"备注";for (EKCalendar *cal in [self.eventStore calendarsForEntityType:EKEntityTypeReminder]) {if ([cal.title isEqualToString:@"自定义"]) {reminder.calendar = cal;}}//保存事件NSError *error = nil;[self.eventStore saveReminder:reminder commit:YES error:&error];NSLog(@"%@", error);
}

同样,对应的也有Reminder的查询,删除等操作。

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的点击加入群聊iOS交流群:789143298 不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术,大家一起交流学习成长!

四、EKEventStore详解

EKEventStore类是EventKit中的核心类,用来对日历和提醒的事件进行操作。其中方法与属性列举如下:

@interface EKEventStore : NSObject
// 获取用户授权情况
+ (EKAuthorizationStatus)authorizationStatusForEntityType:(EKEntityType)entityType;
// 初始化方法
- (id)init;
// 使用指定的来源创建实例对象
- (instancetype)initWithSources:(NSArray<EKSource *> *)sources;
// 请求某个类型的事件访问权限
- (void)requestAccessToEntityType:(EKEntityType)entityType completion:(EKEventStoreRequestAccessCompletionHandler)completion;
// 唯一标识
@property(nonatomic, readonly) NSString *eventStoreIdentifier;
// 代理源  使用initWithSources方法实例化对应
@property (nonatomic, readonly) NSArray<EKSource *> *delegateSources;
// 可用的来源
@property (nonatomic, readonly) NSArray<EKSource *> *sources;
// 通过identifier获取指定的来源对象
- (nullable EKSource *)sourceWithIdentifier:(NSString *)identifier;
// 通过类型来获取所有的日历对象
- (NSArray<EKCalendar *> *)calendarsForEntityType:(EKEntityType)entityType;
// 获取默认的日历对象
@property(nullable, nonatomic, readonly) EKCalendar *defaultCalendarForNewEvents;
- (nullable EKCalendar *)defaultCalendarForNewReminders;
// 通过identifier获取日历对象
- (nullable EKCalendar *)calendarWithIdentifier:(NSString *)identifier;
// 添加一个新的日历,commit参数是都是否立刻提交修改
- (BOOL)saveCalendar:(EKCalendar *)calendar commit:(BOOL)commit error:(NSError **)error;
// 删除某个日历
- (BOOL)removeCalendar:(EKCalendar *)calendar commit:(BOOL)commit error:(NSError **)error;
// 根据identifier获取日程对象
- (nullable EKCalendarItem *)calendarItemWithIdentifier:(NSString *)identifier;
// 获取一组日程对象
- (NSArray<EKCalendarItem *> *)calendarItemsWithExternalIdentifier:(NSString *)externalIdentifier;
// 新建事件 span用来设置对于周期事件本次设置是否影响未来的事件
- (BOOL)saveEvent:(EKEvent *)event span:(EKSpan)span error:(NSError **)error;
- (BOOL)saveEvent:(EKEvent *)event span:(EKSpan)span commit:(BOOL)commit error:(NSError **)error;
// 移出事件
- (BOOL)removeEvent:(EKEvent *)event span:(EKSpan)span error:(NSError **)error;
- (BOOL)removeEvent:(EKEvent *)event span:(EKSpan)span commit:(BOOL)commit error:(NSError **)error;
// 通过identifier获取事件
- (nullable EKEvent *)eventWithIdentifier:(NSString *)identifier;
// 使用给定的NSPredicate进行事件查询
- (NSArray<EKEvent *> *)eventsMatchingPredicate:(NSPredicate *)predicate;
// 使用给定的NSPredicate进行事件枚举
- (void)enumerateEventsMatchingPredicate:(NSPredicate *)predicate usingBlock:(EKEventSearchCallback)block;
// 构造NSPredicate查询对象
- (NSPredicate *)predicateForEventsWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate calendars:(nullable NSArray<EKCalendar *> *)calendars;
// 提醒相关
// 新建一条提醒
- (BOOL)saveReminder:(EKReminder *)reminder commit:(BOOL)commit error:(NSError **)error;
// 删除提醒
- (BOOL)removeReminder:(EKReminder *)reminder commit:(BOOL)commit error:(NSError **)error;
// 进行提醒查询
- (id)fetchRemindersMatchingPredicate:(NSPredicate *)predicate completion:(void (^)(NSArray<EKReminder *> * __nullable reminders))completion;
// 取消某此查询
- (void)cancelFetchRequest:(id)fetchIdentifier;
// 构造查询对象
- (NSPredicate *)predicateForRemindersInCalendars:(nullable NSArray<EKCalendar *> *)calendars;
- (NSPredicate *)predicateForIncompleteRemindersWithDueDateStarting:(nullable NSDate *)startDate ending:(nullable NSDate *)endDate calendars:(nullable NSArray<EKCalendar *> *)calendars;
- (NSPredicate *)predicateForCompletedRemindersWithCompletionDateStarting:(nullable NSDate *)startDate ending:(nullable NSDate *)endDate calendars:(nullable NSArray<EKCalendar *> *)calendars;// 将所有的修改一次性进行提交
- (BOOL)commit:(NSError **)error;
// 重置所有的修改
- (void)reset;
// 刷新来源
- (void)refreshSourcesIfNecessary;
@end

EKEntityType用来描述类型,定义如下:

typedef NS_ENUM(NSUInteger, EKEntityType) {EKEntityTypeEvent,          // 日历类型EKEntityTypeReminder        // 提醒类型
};

EKAuthorizationStatus用来描述用户授权状态:

typedef NS_ENUM(NSInteger, EKAuthorizationStatus) {EKAuthorizationStatusNotDetermined = 0,   // 用户尚未选择EKAuthorizationStatusRestricted,          // 应用无权访问EKAuthorizationStatusDenied,              // 用户拒绝授权EKAuthorizationStatusAuthorized,          // 用户授权
} ;

EKSpan用来描述所影响事件类型:

typedef NS_ENUM(NSInteger, EKSpan) {EKSpanThisEvent,     // 只影响本次事件EKSpanFutureEvents   // 对未来的事件也会产生影响
};

五、EKSource类详解

首先,EKSource描述了,例如某些日历是系统默认创建的,用户没有权限进行修改或删除,某些日历是用户自定义创建的,还有些可能来自云端,这个类继承自EKObject类,首先先看EKObject类的定义:

@interface EKObject : NSObject
// 数据对象是否有修改
@property (nonatomic, readonly) BOOL hasChanges;
// 是否是一个新的数据对象(为存储到日历或提醒中)
- (BOOL)isNew;
// 重置数据 将所有属性清空
- (void)reset;
// 回滚未提交的操作
- (void)rollback;
// 刷新数据
- (BOOL)refresh;
@end

EKSource是EKObject的子类,其中封装属性和方法如下:

@interface EKSource : EKObject
// 来源对象的ID 唯一标识
@property(nonatomic, readonly) NSString        *sourceIdentifier;
// 来源对象的类型
@property(nonatomic, readonly) EKSourceType     sourceType;
// 来源对象的标题
@property(nonatomic, readonly) NSString        *title;
// 此来源对象中所包含的日历对象
@property(nonatomic, readonly) NSSet<EKCalendar *> *calendars;
// 获取此来源对象中某个类型的日历 (日历或提醒)
- (NSSet<EKCalendar *> *)calendarsForEntityType:(EKEntityType)entityType;
@end

EKSourceType枚举如下:

typedef NS_ENUM(NSInteger, EKSourceType) {EKSourceTypeLocal,     // 本地EKSourceTypeExchange,  // 交换EKSourceTypeCalDAV,    // CalDAV或iCloudEKSourceTypeMobileMe,  // MobileMeEKSourceTypeSubscribed,// 订阅EKSourceTypeBirthdays  // 生日
};

六、EKCalendar类详解

EKCalendar是具体的日历对象,开发者可以对自定义的日历进行读写操作,其也是继承自EKObject对象,解析如下:

@interface EKCalendar : EKObject
// 通过制定的EKEventStore对象创建一个新的日历对象
+ (EKCalendar*)calendarWithEventStore:(EKEventStore *)eventStore;
// 创建某个类型的日历对象 (日历或提醒)
+ (EKCalendar *)calendarForEntityType:(EKEntityType)entityType eventStore:(EKEventStore *)eventStore;
// 当前日历对象所属于的来源
@property(null_unspecified, nonatomic, strong) EKSource        *source;
// 日历对象的ID
@property(nonatomic, readonly) NSString         *calendarIdentifier;
// 日历对象的标题  会在 日历 应用 或 提醒 应用中显示
@property(nonatomic, copy)     NSString          *title;
// 当前日历对象的类型
/*
typedef NS_ENUM(NSInteger, EKCalendarType) {EKCalendarTypeLocal,EKCalendarTypeCalDAV,EKCalendarTypeExchange,EKCalendarTypeSubscription,EKCalendarTypeBirthday
};
*/
@property(nonatomic, readonly)     EKCalendarType     type;
// 当前日历是否支持编辑
@property(nonatomic, readonly) BOOL allowsContentModifications;
// 当前日历是否为订阅类型
@property(nonatomic, readonly, getter=isSubscribed) BOOL subscribed;
// 当前日历对象是否可变
@property(nonatomic, readonly, getter=isImmutable) BOOL immutable;
// 对应的提示颜色
@property(null_unspecified, nonatomic) CGColorRef CGColor;
// 支持的事件状态
/*
typedef NS_OPTIONS(NSUInteger, EKCalendarEventAvailabilityMask) {EKCalendarEventAvailabilityNone         = 0,    // calendar doesn't support event availabilityEKCalendarEventAvailabilityBusy         = (1 << 0),EKCalendarEventAvailabilityFree         = (1 << 1),EKCalendarEventAvailabilityTentative    = (1 << 2),EKCalendarEventAvailabilityUnavailable  = (1 << 3),
};
*/
@property(nonatomic, readonly) EKCalendarEventAvailabilityMask supportedEventAvailabilities;
// 支持的日历类型
/*
typedef NS_OPTIONS(NSUInteger, EKEntityMask) {EKEntityMaskEvent      = (1 << EKEntityTypeEvent),EKEntityMaskReminder   = (1 << EKEntityTypeReminder)
};
*/
@property(nonatomic, readonly) EKEntityMask allowedEntityTypes;
@end

七、EKEvent与EKReminder

EKEvent与EKReminder类在设计上是平行的两个类,前面的示例代码中也有介绍。EKEvent对应系统日历中的事件,EKReminder对应系统提醒应用中的事件。他们都继承自EKCalendarItem类,EKCalendarItem也是EKObject的子类,这个类解析如下:

@interface EKCalendarItem : EKObject
// UUID 事件的唯一标识
@property(nonatomic, readonly) NSString *UUID;
// 事件所属于的日历
@property(nonatomic, strong, null_unspecified) EKCalendar *calendar;
// 事件的ID
@property(nonatomic, readonly) NSString *calendarItemIdentifier;
// 事件的标题
@property(nonatomic, copy, null_unspecified) NSString *title;
// 地理位置
@property(nonatomic, copy, nullable) NSString *location;
// 备注信息
@property(nonatomic, copy, nullable) NSString *notes;
// 网址URL
@property(nonatomic, copy, nullable) NSURL *URL;
// 最后一次更改时间
@property(nonatomic, readonly, nullable) NSDate *lastModifiedDate;
// 事件创建的时间
@property(nonatomic, readonly, nullable, strong) NSDate *creationDate;
// 时区
@property(nonatomic, copy, nullable) NSTimeZone *timeZone;
// 是否有闹钟提醒
@property(nonatomic, readonly) BOOL hasAlarms;
// 是否包含重复提醒的规则
@property(nonatomic, readonly) BOOL hasRecurrenceRules;
// 是否包含参会人信息
@property(nonatomic, readonly) BOOL hasAttendees;
// 是否包含备注
@property(nonatomic, readonly) BOOL hasNotes;
// 参会人信息
@property(nonatomic, readonly, nullable) NSArray<__kindof EKParticipant *> *attendees;
// 闹钟提醒信息
@property(nonatomic, copy, nullable) NSArray<EKAlarm *> *alarms;
// 添加闹钟规则
- (void)addAlarm:(EKAlarm *)alarm;
// 删除闹钟规则
- (void)removeAlarm:(EKAlarm *)alarm;
// 包含的定期规则
@property(nonatomic, copy, nullable) NSArray<EKRecurrenceRule *> *recurrenceRules;
// 添加定期规则
- (void)addRecurrenceRule:(EKRecurrenceRule *)rule;
// 删除定期规则
- (void)removeRecurrenceRule:(EKRecurrenceRule *)rule;
@end

上面类中有引用到一些其他的核心类,如EKParticipant、EKAlarm和EKRecurrenceRule,后面会介绍。

EKEvent是EKCalendarItem的子类,其对应日历应用中的事件,解析如下:

@interface EKEvent : EKCalendarItem
// 创建一个新的事件对象
+ (EKEvent *)eventWithEventStore:(EKEventStore *)eventStore;
// 系统分类的事件ID
@property(null_unspecified, nonatomic, readonly) NSString *eventIdentifier;
// 是否是一个全天事件
@property(nonatomic, getter=isAllDay) BOOL allDay;
// 事件开始日期
@property(null_unspecified, nonatomic, copy) NSDate *startDate;
// 事件结束日期
@property(null_unspecified, nonatomic, copy) NSDate *endDate;
// 触发型事件 到达某个地理位置后触发
@property(nonatomic, copy, nullable) EKStructuredLocation *structuredLocation;
// 与另一个事件的开始事件进行比较
- (NSComparisonResult)compareStartDateWithEvent:(EKEvent *)other;
// 事件的组织者
@property(nonatomic, readonly, nullable) EKParticipant *organizer;
// 事件行为状态
@property(nonatomic) EKEventAvailability    availability;
// 事件确认状态
/*
typedef NS_ENUM(NSInteger, EKEventStatus) {EKEventStatusNone = 0,EKEventStatusConfirmed,EKEventStatusTentative,EKEventStatusCanceled,
};
*/
@property(nonatomic, readonly) EKEventStatus          status;
// 事件是否是独立的
@property(nonatomic, readonly) BOOL isDetached;
// 事件发生时间
@property(null_unspecified, nonatomic, readonly) NSDate *occurrenceDate;
// 刷新
- (BOOL)refresh;
// 对于生日事件 对应的生日联系人ID
@property(nonatomic, readonly, nullable) NSString *birthdayContactIdentifier;
@end

EKReminder与EKEvent类似,其对应系统的提醒事宜应用中的事件:

@interface EKReminder : EKCalendarItem
// 新建提醒事件
+ (EKReminder *)reminderWithEventStore:(EKEventStore *)eventStore;
// 开始时间
@property(nonatomic, copy, nullable) NSDateComponents *startDateComponents;
// 发生时间
@property(nonatomic, copy, nullable) NSDateComponents *dueDateComponents;
// 是否已完成
@property(nonatomic, getter=isCompleted) BOOL completed;
// 完成时间
@property(nonatomic, copy, nullable) NSDate *completionDate;
// 优先级 1-4 为高  5 为中  6-9为低
@property(nonatomic) NSUInteger priority;
@end

八、EKAlarm与EKStructuredLocation

EKAlarm对应闹钟对象,事件可以绑定闹钟提醒,解析如下:

@interface EKAlarm : EKObject
// 通过绝对时间创建闹钟
+ (EKAlarm *)alarmWithAbsoluteDate:(NSDate *)date;
// 通过与现在的相对事件创建闹钟
+ (EKAlarm *)alarmWithRelativeOffset:(NSTimeInterval)offset;
// 与现在的相对时间
@property(nonatomic) NSTimeInterval relativeOffset;
// 绝对时间
@property(nonatomic, copy, nullable) NSDate *absoluteDate;
// 地理位置触发的闹钟,对应的地理位置
@property(nonatomic, copy, nullable) EKStructuredLocation   *structuredLocation;
// 触发方式
/*
typedef NS_ENUM(NSInteger, EKAlarmProximity) {EKAlarmProximityNone,EKAlarmProximityEnter,   // 进入触发条件EKAlarmProximityLeave    // 离开触发条件
};
*/
@property(nonatomic) EKAlarmProximity    proximity;
// 闹钟类型
/*
typedef NS_ENUM(NSInteger, EKAlarmType) {EKAlarmTypeDisplay,EKAlarmTypeAudio,EKAlarmTypeProcedure,EKAlarmTypeEmail
};
*/
@property(nonatomic, readonly) EKAlarmType type;
// 提醒的邮件地址
@property(nonatomic, copy, nullable) NSString *emailAddress;
// 提醒的音效名称
@property(nonatomic, copy, nullable) NSString *soundName;
// 提醒后打开的网页
@property(nonatomic, copy, nullable) NSURL *url;
@end

EKStructuredLocation用来描述地区区域结构,如下:

@interface EKStructuredLocation : EKObject
// 通过标题创建
+ (instancetype)locationWithTitle:(NSString *)title;
// 通过地图点创建
+ (instancetype)locationWithMapItem:(MKMapItem *)mapItem NS_AVAILABLE(10_11, 9_0);
// 标题
@property(nullable, nonatomic, strong) NSString     *title;
// 经纬度地理信息
@property(nonatomic, strong, nullable) CLLocation   *geoLocation;
// 半径
@property(nonatomic) double                radius;
@end

九、EKParticipant类详解

EKParticipant类是与事件相关的联系人数据类,解析如下:

@interface EKParticipant : EKObject
// 网址
@property(nonatomic, readonly) NSURL           *URL;
// 姓名
@property(nonatomic, readonly, nullable) NSString        *name;
// 状态
/*
typedef NS_ENUM(NSInteger, EKParticipantStatus) {EKParticipantStatusUnknown,  // 未知EKParticipantStatusPending,  // 等待处理EKParticipantStatusAccepted, // 接收EKParticipantStatusDeclined, // 拒绝EKParticipantStatusTentative,// 尝试EKParticipantStatusDelegated,// 代理EKParticipantStatusCompleted,// 完成EKParticipantStatusInProcess // 进行中
};
*/
@property(nonatomic, readonly) EKParticipantStatus participantStatus;
// 人员的角色
/*
typedef NS_ENUM(NSInteger, EKParticipantRole) {EKParticipantRoleUnknown,        // 未知EKParticipantRoleRequired,       // 必要的EKParticipantRoleOptional,       // 可选参与的EKParticipantRoleChair,          // 主持人EKParticipantRoleNonParticipant  // 参与者
};
*/
@property(nonatomic, readonly) EKParticipantRole participantRole;
// 参与人类型
/*
typedef NS_ENUM(NSInteger, EKParticipantType) {EKParticipantTypeUnknown,EKParticipantTypePerson,EKParticipantTypeRoom,EKParticipantTypeResource,EKParticipantTypeGroup
};
*/
@property(nonatomic, readonly) EKParticipantType participantType;
// 是否是当前用户
@property(nonatomic, readonly, getter=isCurrentUser) BOOL currentUser;
// 用来查找联系人的NSPredicate对象
@property(nonatomic, readonly) NSPredicate *contactPredicate;

推荐

iOS开发之EventKit框架的应用相关推荐

  1. iOS开发之AVKit框架使用

    2019独角兽企业重金招聘Python工程师标准>>> iOS开发之AVKit框架使用 一.引言 在iOS开发框架中,AVKit是一个非常上层,偏应用的框架,它是基于AVFounda ...

  2. iOS开发之Accounts框架详解

    2019独角兽企业重金招聘Python工程师标准>>> iOS开发之Accounts框架详解 Accounts框架是iOS原生提供的一套账户管理框架,其支持Facebook,新浪微博 ...

  3. (0068)iOS开发之AutoLayout框架Masonry使用心得

    苹果官方给出了一些有关自动布局的建议 不论用interfaceBuilder还是用代码来实现自动布局,这些建议都是适用的. (1)不用view的frame.bounds.center来指定view的形 ...

  4. iOS开发之Masonry框架-源码解析

    Masonry是iOS在控件布局中经常使用的一个轻量级框架.Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让 ...

  5. iOS开发之Masonry框架源码解析

    Masonry是iOS在控件布局中经常使用的一个轻量级框架,Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让 ...

  6. iOS开发之Masonry框架源码深度解析

    Masonry是iOS在控件布局中经常使用的一个轻量级框架,Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让 ...

  7. iOS开发之ReplayKit框架学习

    ReplayKit简介 在iOS 9中,ReplayKit 是一款全新的框架,可谓是游戏开发者(开发商)的福音.它可以让玩家更便捷地记录游戏进度或数据以及分享的功能.除此之外更强大的是:ReplayK ...

  8. iOS开发之Masonry框架-使用方法须知

    目录 常用的属性与常量 Masonry使用注意 约束的优先级 Masonry添加约束的方法 修改约束 在哪创建我的约束 创建约束技巧: Masonry是一个轻量级的布局框架,它拥有自己的描述语法(采用 ...

  9. 李洪强iOS开发之Foundation框架—结构体

    Foundation框架-结构体 一.基本知识 Foundation-基础框架.框架中包含了很多开发中常用的数据类型,如结构体,枚举,类等,是其他ios框架的基础. 如果要想使用foundation框 ...

最新文章

  1. 我们为什么要分库分表?
  2. 大白话详解Spring Security认证流程
  3. linux clock命令,Linux中clock命令起什么作用呢?
  4. 通过正则表达式验证日期
  5. Web前端技术分享:img标签下方出现空隙的问题解决方案
  6. plex实现流媒体服务器_如何从Plex Media Server离线查看下载和同步媒体
  7. [ASP.NET Core MVC] 如何实现运行时动态定义Controller类型?
  8. 计算机用户文件夹怎么改名称,win10修改用户名文件夹方法_win10怎么改用户文件夹名称-win7之家...
  9. LeetCode——最小栈
  10. 论文及文献资料的搜集好去处---子午学术论坛
  11. runnerw.exe: CreateProcess failed with error 193: %1 问题定位-idea
  12. access抓取数据_网页数据抓取之当当网
  13. mouseover mouseout和mouseenter mouseleave的区别
  14. win10计算机记录,Win10新版计算器用法介绍
  15. 爬虫【11】易班刷网薪系统
  16. java简历校园经历_简历校园经历如何编
  17. 隐马尔可夫模型(一):模型介绍
  18. 华为路由交换——三层交换机与路由器之间链路实现交互
  19. 低学历转行3D建模有前途吗,游戏3D建模怎么样?
  20. Sendmail大全

热门文章

  1. Python+Flask+MySQL实例——简单的成语词典实现
  2. 你见过代码里面的“龟派气功”吗?
  3. bugku学习5:Simple_SSTI_2(web)
  4. CSS div footer,网站Footer导航完美自动固定在底部div+css
  5. wps多人协作的意义_怎么能快速体验WPS加载项
  6. armbian安装pillow报错解决
  7. java iterator remove_Iterator remove()详解
  8. 网页游戏斩仙服务器不存在什么意思,QQ斩仙3月11日部分服务器合服公告
  9. 哔哩哔哩Allen老师通用后台管理系统
  10. opencv调用TensorFlow1.x训练的pb模型