轉:http://blog.csdn.net/BAOU1371/article/details/51993581
直接上代碼說明如何使用,后面有詳細的介紹
主要使用Eventkit事件庫的EKEventStore類
該類負責日歷和提醒事件的管理,可以簡單理解為數據庫,可以對事件進行增刪改查。
因為它就像數據庫一樣,頻繁的開啟,關閉會影響效率,所以如果你的程序需要頻繁操作日歷和提醒,建議僅生成該對象一次,僅用一個對象進行操作。
@interface ViewController () @end @implementation ViewController - (void)viewDidLoad{ [super viewDidLoad]; [self addEventNotify:[NSDate dateWithTimeIntervalSinceNow:60] title:@"測試事件"]; } -(void)addEventNotify:(NSDate *)date title:(NSString *)title { //生成事件數據庫對象 EKEventStore *eventDB = [[EKEventStore alloc] init]; //申請事件類型權限 [eventDB requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) { if (granted) { //授權是否成功 EKEvent *myEvent = [EKEvent eventWithEventStore:eventDB]; //創建一個日歷事件 myEvent.title = title; //標題 myEvent.startDate = date; //開始date required myEvent.endDate = date; //結束date required [myEvent addAlarm:[EKAlarm alarmWithAbsoluteDate:date]]; //添加一個鬧鍾 optional [myEvent setCalendar:[eventDB defaultCalendarForNewEvents]]; //添加calendar required NSError *err; [eventDB saveEvent:myEvent span:EKSpanThisEvent error:&err]; //保存 } }]; } -(void)addReminderNotify:(NSDate *)date title:(NSString *)title { EKEventStore *eventDB = [[EKEventStore alloc] init]; //申請提醒權限 [eventDB requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError * _Nullable error) { if (granted) { //創建一個提醒功能 EKReminder *reminder = [EKReminder reminderWithEventStore:eventDB]; //標題 reminder.title = title; //添加日歷 [reminder setCalendar:[eventDB defaultCalendarForNewReminders]]; NSCalendar *cal = [NSCalendar currentCalendar]; [cal setTimeZone:[NSTimeZone systemTimeZone]]; NSInteger flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay |NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; NSDateComponents* dateComp = [cal components:flags fromDate:date]; dateComp.timeZone = [NSTimeZone systemTimeZone]; reminder.startDateComponents = dateComp; //開始時間 reminder.dueDateComponents = dateComp; //到期時間 reminder.priority = 1; //優先級 EKAlarm *alarm = [EKAlarm alarmWithAbsoluteDate:date]; //添加一個車鬧鍾 [reminder addAlarm:alarm]; NSError *err; [eventDB saveReminder:reminder commit:YES error:&err]; if (err) { } } }]; }
下面是Eventkit的具體介紹
- Eventkit開發包介紹
-
事件提醒開發包(EventKit)由事件庫、事件源、日歷和事件/提醒組成,他們的關系是:事件庫用於直接操作日歷數據庫,日歷數據庫中的數據按事件源、日歷和事件/提醒三級進行分類組織。每個事件源對應一個准帳戶,該帳戶下可以有多個日歷,日歷分兩類,一類是用於存儲事件的日歷,一類是用於存儲提醒的日歷。這里所說的存儲,實際就是分類,反過來的,根據子項對父項進行分類。就如兩口缸,一口裝水,一口沙子一樣,這個缸就是上面提及的日歷,水相當於事件,沙子相當於提醒。一戶人家的院子里可以擺好多口缸,這個院子就相當於帳戶,有兩個默認帳戶,一個是Local,一個是Other。帳戶的類型,還可能有iCloud或Gmail帳號等,一般是郵箱附帶的,所以就默認對應着該郵箱地址了。就像 大戶人家的總管,管好每戶的院子,還有每個院子里的缸一樣,事件庫直接管理所有的帳戶和日歷,還有日歷下的事件或提醒。管理包括增加、修改、查詢、刪除(CURD)。
* Eventkit事件庫結構
事件庫框架授權訪問用戶的Calendar.app
和Reminders.app
應用的信息。盡管是用兩個不同的應用顯示用戶的日歷和提醒數據,但確是同一個框架維護這份數據。同樣地,存儲這份數據的數據庫叫做日歷數據庫,同時容納日歷和提醒信息。
事件庫不但允許你的應用獲取用戶已經存在的日歷及提醒數據,而且它可以讓你的應用為任何日歷創建新的事件和提醒。另外,事件庫讓用戶可以編輯和刪除他們的事件和提醒(整體叫做“日歷項”)。更高級的任務,諸如添加鬧鍾或指定循環事件,也可以使用事件庫完成。如果日歷數據庫有來自你的應用外部的更改發生,事件庫可以通過通知監測到,這樣你的應用可以做出適當的響應。使用事件庫對日歷項所做的更改會自動地同步到相關的日歷。 -
- 圖1-1事件庫結構圖
使用Eventkit事件庫操作日歷
事件(NSCalendar)
-
讀寫日歷事件
你可以使用 EKEventStore 類從用戶的日歷數據庫中獲取、創建、編輯和刪除事件。你可以獲取匹配你提供的謂詞的事件自定義的一組事件,或通過唯一標識獲取一個單獨的事件。你獲取到一個事件后,可以使用 EKEvent 類的屬性獲取訪問該事件相關的日歷信息。同樣的,你可以通過設置 EKEvent 類的屬性來修改該事件的日歷信息。 -
連接到事件庫
在 iOS 6 及以后版本,你必須在事件庫初始化后,使用requestAccessToEntityType:completion:
方法請求使用用戶的日歷數據庫。請求訪問某個實體類型會異步提示用戶允許或禁止你的應用使用他們的日歷信息。你應該處理用戶授權或禁止你的應用訪問權的各種狀況:
[store requestAccessToEntityType:EKEntityTypeEvent
completion:^(BOOL granted, NSError *error) { // handle access here }];
注意
EKEventStore 對象需要相對較大量的時間來初始化和釋放。因此,你不應該為每一個事件相關的任務都初始化和釋放事件庫。相反,在你的應用加載時,初始化一個事件庫,然后反復地使用這一個來確保連接一直可用。事件庫實例不應該在其它事件開發包相對的對象釋放前被釋放,否則可能發生意想不到的狀態。
-
獲取事件
有兩種方式獲取事件。通過謂詞或搜索查詢獲取,會返回零個或多個與給定查詢匹配的事件。通過唯一標識獲取會返回與給定標識相符的唯一的一個事件。 -
注意
從日歷數據庫獲取事件並不一定按時間順序返回。要通過日期排序 EKEvent 對象的數組,可以在數組上調用 sortedArrayUsingSelector: 方法,並提供 compareStartDateWithEvent: 方法的選擇器。 -
使用謂詞
通常是要獲得屬於某一日期范圍的事件。 EKEventStore 的eventsMatchingPredicate:
方法獲取屬於你提供的謂詞中指定的日期范圍的所有事件。
注意:盡管eventsMatchingPredicate:
方法接受一個 NSPredicate類型的參數,但你必須提供一個用 EKEventStore 的方法predicateForEventsWithStartDate:endDate:calendars:
創建的謂詞。
//以下代碼描述了如何獲取發生在一天前和當前之后一年之內的所有事件。 // 獲取適當的日期(Get the appropriate calendar) NSCalendar *calendar = [NSCalendar currentCalendar]; // 創建起始日期組件(Create the start date components) NSDateComponents *oneDayAgoComponents = [[NSDateComponents alloc] init]; oneDayAgoComponents.day = -1; NSDate *oneDayAgo = [calendar dateByAddingComponents:oneDayAgoComponents toDate:[NSDate date] options:0]; // 創建結束日期組件(Create the end date components) NSDateComponents *oneYearFromNowComponents = [[NSDateComponents alloc] init]; oneYearFromNowComponents.year = 1; NSDate *oneYearFromNow = [calendar dateByAddingComponents:oneYearFromNowComponents toDate:[NSDate date] options:0]; // 用事件庫的實例方法創建謂詞 (Create the predicate from the event store's instance method) NSPredicate *predicate = [store predicateForEventsWithStartDate:oneDayAgo endDate:oneYearFromNow calendars:nil]; // 獲取所有匹配該謂詞的事件(Fetch all events that match the predicate) NSArray *events = [store eventsMatchingPredicate:predicate];
你可以指定一個日歷的子集來搜索,這需要傳遞一個 EKCalendar 對象的數組作為 predicateForEventsWithStartDate:endDate:calendars:
方法的calendars
參數。你可以從事件庫的 calendarsForEntityType:
方法獲得用戶的不同類型的日歷。如果傳一個 nil 值,那么就是告訴這個方法獲取用戶的所有日歷。因為方法 eventsMatchingPredicate:
是同步的,而你可能並不想在你的應用主線程中運行它。如果要異步執行的話,那么使用 dispatch_async 函數或使用一個 NSOperation 對象,就可以在另一個線程中運行該方法了。
* 使用唯一標識
如果你之前使用謂詞獲得了一個事件並知道它的唯一標識,那么你可以使用 EKEventStore 的 eventWithIdentifier:
方法來再次獲取該事件。如果它是一個循環事件,那么這個方法就會返回第一次出現的該事件。你可以使用屬性 eventIdentifier
獲得事件的唯一標識。
-
創建及編輯事件
使用 事件EKEvent 的eventWithEventStore:
方法創建一個新的事件。
你可以通過設置一個新的事件或先前從日歷數據庫獲取的事件的對應屬性來編輯事件。你可以編輯的詳細內容包括:- 事件的標題用
title
屬性 - 事件的起始日期用
startDate
和endDate
屬性 - 與事件關聯的日歷用屬性
calendar
- 與事件相關的鬧鍾用
alarms
屬性 (參見 “配置鬧鍾” 以獲得更多詳細信息) - 如果一個事件是循環事件,那么它的循環規則用屬性 recurrenceRules (參見 “創建循環事件” 以獲得更多詳細信息)
- 事件的標題用
-
保存和移除事件
如果你的應用修改用戶的日歷數據庫,它必須在這之前先從用戶獲得確認。應用在未得到用戶的特定指示的情況下決不可能修改日歷數據庫。
你對事件的修改不是持久化的,直到你保存它們為止。使用 EKEventStore 的saveEvent:span:commit:error:
方法保存你的修改到日歷數據庫中。如果你要從日歷數據庫移除事件,使用 EKEventStore 的removeEvent:span:commit:error:
方法。無論你保存或移除事件,各自實現的方法都會自動所做的修改到該事件所屬於的日歷(CalDav、Exchange等等)。
如果你保存一個循環事件,你可以通過給saveEvent:span:commit:error:
方法的參數 span 指定 EKSpanFutureEvents 來使你的更改應用到所有未來出現的該事件中。同樣地,你也可以指定removeEvent:span:commit:error:
方法的 span 參數值為EKSpanFutureEvents
來移除一個事件的所有未來的出現。
注意:如果你給 commit 參數傳了 NO 值,那么要確保稍侯調用 commit: 方法以持久保存你的更改(譯者注:默認傳 YES 會立即持久保存更改)。 -
執行批量事件操作
你可以在 EKEventStore 的enumerateEventsMatchingPredicate:usingBlock:
方法執行給定的謂詞匹配的所有事件上執行同一個操作。你必須為上述方法使用 EKEventStore 的predicateForEventsWithStartDate:endDate:calendars:
方法創建謂詞。你提供的操作是EKEventSearchCallback
類型的塊。
typedef void (^EKEventSearchCallback)(EKEvent *event, BOOL *stop);
塊接收兩個參數:
event
:表示當前被操作的事件
stop
:一個布爾值,它決定當前塊返回后 enumerateEventsMatchingPredicate:usingBlock: 方法是否應該停止繼續處理事件。如果是 YES,那么與該謂詞匹配的任何未處理的事件仍保持未處理狀態。
注意:使用該方法會引起對用戶的日歷數據庫的有效的修改。確認在你向用戶請求批准時,讓用戶清楚地知道你所要執行的操作。
使用Eventkit事件庫操作提醒事項
事件(EKReminder)
-
讀寫提醒事項
提醒就是一些可以關聯到特定時間或位置的任務。他們與日歷事件很相似,但可以被標識為完成並且可以不必跨躍一段確切的時間。
因為EKReminder
繼承自EKCalendarItem
,所以你可以在提醒上執行與在事件上一樣的方法,諸如使用addAlarm:
方法添加一個鬧鍾,或使用addRecurrenceRule:
方法設置一個循環規則。 -
獲取提醒
和事件一樣,你必須先建立與事件庫的連接,才能訪問已存在的提醒。
在 iOS 6 及以后的版本中,事件庫初始化后,你必須使用requestAccessToEntityType:completion:
請求對用戶日歷數據庫的訪問權。請求某一實體類型的訪問權會提示用戶允許或禁止你的應用使用日歷信息。你應該處理用戶授權或禁止訪問每種情況:
[store requestAccessToEntityType:EKEntityTypeReminder
completion:^(BOOL granted, NSError *error) { // handle access here }];
- 搜索
提醒事項
的事件 - 創建及編輯提醒
- 保存和移除提醒
以上三點都和設置日歷類似,方法就是將Calendar
替換成Reminder
配置鬧鍾
鬧鍾提醒是將一個與前面日歷事件或者提醒事項配套的一個鬧鈴提示。通常一個鬧鈴事件就是當應用運行時,鬧鈴作為一種notification來提示用戶當前未辦的事件(schedules)。如果一個鬧鈴是被設置在日歷事件(calendar event)或者是提醒事件(reminder)中的,這個鬧鈴通知就會從這個應用發出一個notification。鬧鈴可以是根據時間設計的,在特定的事件就會響,鬧鈴也可以是地點提醒的(location-based),當用戶到達一個地理圍欄geofence(crossing a geofence)就會響。
鬧鈴事件可以添加到日歷中和提醒事項中。
注意:以上說的鬧鈴並不是一種UILocalNotification服務,而是一種配套日歷事件和提醒事項的事件。
- 添加和移除鬧鈴
你可以通過addAlarm:
方法添加一個鬧鍾,鬧鈴可以根據一個確定的事件創建,也可以根據一個時間的推移(offset)來設置啟動時間。鬧鈴創建的時間必須比事件發生的時間早或者同時發生。
你可以通過removeAlarm:
方法移除一個事件的一個鬧鍾。