iOS利用代碼添加事件到系統日曆中

簡單實現示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#import <EventKit/EventKit.h><br><br>- (void)saveEvent:(id)sender {
       
    //事件市場
    EKEventStore *eventStore = [[EKEventStore alloc] init];
     
    //6.0及以上通過下面方式寫入事件
    if ([eventStore respondsToSelector:@selector(requestAccessToEntityType:completion:)])
    {
        // the selector is available, so we must be on iOS 6 or newer
        [eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (error)
                {
                    //錯誤細心
                    // display error message here
                }
                else if (!granted)
                {
                    //被用戶拒絕,不允許訪問日曆
                    // display access denied error message here
                }
                else
                {
                    // access granted
                    // ***** do the important stuff here *****
                     
                    //事件保存到日曆
                     
                     
                    //創建事件
                    EKEvent *event  = [EKEvent eventWithEventStore:eventStore];
                    event.title     = @"哈哈哈,我是日曆事件啊";
                    event.location = @"我在杭州西湖區留和路";
                     
                    NSDateFormatter *tempFormatter = [[NSDateFormatter alloc]init];
                    [tempFormatter setDateFormat:@"dd.MM.yyyy HH:mm"];
                     
                    event.startDate = [[NSDate alloc]init ];
                    event.endDate   = [[NSDate alloc]init ];
                    event.allDay = YES;
                     
                    //添加提醒
                    [event addAlarm:[EKAlarm alarmWithRelativeOffset:60.0f * -60.0f * 24]];
                    [event addAlarm:[EKAlarm alarmWithRelativeOffset:60.0f * -15.0f]];
                     
                    [event setCalendar:[eventStore defaultCalendarForNewEvents]];
                    NSError *err;
                    [eventStore saveEvent:event span:EKSpanThisEvent error:&err];
                     
                    UIAlertView *alert = [[UIAlertView alloc]
                                          initWithTitle:@"Event Created"
                                          message:@"Yay!?"
                                          delegate:nil
                                          cancelButtonTitle:@"Okay"
                                          otherButtonTitles:nil];
                    [alert show];
                     
                    NSLog(@"保存成功");
                     
                }
            });
        }];
    }
    else
    {
        // this code runs in iOS 4 or iOS 5
        // ***** do the important stuff here *****
         
        //4.0和5.0通過下述方式添加
         
        //保存日曆
        EKEvent *event  = [EKEvent eventWithEventStore:eventStore];
        event.title     = @"哈哈哈,我是日曆事件啊";
        event.location = @"我在杭州西湖區留和路";
         
        NSDateFormatter *tempFormatter = [[NSDateFormatter alloc]init];
        [tempFormatter setDateFormat:@"dd.MM.yyyy HH:mm"];
         
        event.startDate = [[NSDate alloc]init ];
        event.endDate   = [[NSDate alloc]init ];
        event.allDay = YES;
         
         
        [event addAlarm:[EKAlarm alarmWithRelativeOffset:60.0f * -60.0f * 24]];
        [event addAlarm:[EKAlarm alarmWithRelativeOffset:60.0f * -15.0f]];
         
        [event setCalendar:[eventStore defaultCalendarForNewEvents]];
        NSError *err;
        [eventStore saveEvent:event span:EKSpanThisEvent error:&err];
         
        UIAlertView *alert = [[UIAlertView alloc]
                              initWithTitle:@"Event Created"
                              message:@"Yay!?"
                              delegate:nil
                              cancelButtonTitle:@"Okay"
                              otherButtonTitles:nil];
        [alert show];
         
        NSLog(@"保存成功");
         
    }
}

 

分析:事件提醒開發包(EventKit)由事件庫、事件源、日曆和事件/提醒組成,他們的關係是:事件庫用於直接操作日曆數據庫,日曆數據庫中的數據按事件源、日曆和事件/提醒三級進行分類組織。每個事件源對應一個準帳戶,該帳戶下可以有多個日曆,日曆分兩類,一類是用於存儲事件的日曆,一類是用於存儲提醒的日曆。這裏所說的存儲,實際就是分類,反過來的,根據子項對父項進行分類。就如兩口缸,一口裝水,一口沙子一樣,這個缸就是上面提及的日曆,水相當於事件,沙子相當於提醒。一戶人家的院子裏可以擺好多口缸,這個院子就相當於帳戶,有兩個默認帳戶,一個是Local,一個是Other。帳戶的類型,還可能有iCloud或Gmail帳號等,一般是郵箱附帶的,所以就默認對應着該郵箱地址了。就像 大戶人家的總管,管好每戶的院子,還有每個院子裏的缸一樣,事件庫直接管理所有的帳戶和日曆,還有日曆下的事件或提醒。管理包括增加、修改、查詢、刪除(CURD)。
  • 日曆和提醒入門(Introduction to Calendars and Reminders) 

事件庫框架授權訪問用戶的 Calendar.app 和 Reminders.app 應用的信息。儘管是用兩個不同的應用顯示用戶的日曆和提醒數據,但確是同一個框架維護這份數據。同樣地,存儲這份數據的數據庫叫做日曆數據庫,同時容納日曆和提醒信息。

The Event Kit framework grants access to users’ Calendar.app and Reminders.app information. Although two different apps display users’ calendar and reminder data, the same framework manipulates the data. Similarly, the database that stores this data, called the Calendar database, holds both calendar and reminder information.

圖示 1-1 事件庫結構 Figure I-1 Event Kit architecture

事件庫不但允許你的應用獲取用戶已經存在的日曆及提醒數據,而且它可以讓你的應用爲任何日曆創建新的事件和提醒。另外,事件庫讓用戶可以編輯和刪除他們的事件和提醒(整體叫做“日曆項”)。更高級的任務,諸如添加鬧鐘或指定循環事件,也可以使用事件庫完成。如果日曆數據庫有來自你的應用外部的更改發生,事件庫可以通過通知監測到,這樣你的應用可以做出適當的響應。使用事件庫對日曆項所做的更改會自動地同步到相關的日曆(CalDAV - 是一種效率手冊同步協議,有些效率手冊 如 Apple iCal、Mozilla Lightning/Sunbird 使用這一協議使其信息能與其它效率手冊 如 Yahoo! 效率手冊 進行交換;Exchange 等)。

本文檔描述事件庫的概念及通用的編程任務。如果你想要從你的應用來顯示或編輯日曆事件和/或提醒數據,那麼你應該閱讀本文檔。事件庫提供了有限的對用戶日曆數據庫的訪問;但它並未包含期望實現完整特性的日曆或提醒應用所需的每一個功能,諸如出席者和帳戶。

Event Kit not only allows your app to retrieve users’ existing calendar and reminder data, but it also lets your app create new events and reminders for any of their calendars. In addition, Event Kit lets users edit and delete their events and reminders (collectively known as “calendar items”). More advanced tasks, such as adding alarms or specifying recurring events, can be achieved with Event Kit as well. If a change to the Calendar database occurs from outside of your app, Event Kit is able to detect the change by notification so your app can act appropriately. Changes made to calendar items with Event Kit are automatically synced to the associated calendar (CalDAV, Exchange, and so on).

This document describes Event Kit concepts and common programming tasks. You should read this document if you want to display or edit calendar events and/or reminder data from within your app. Event Kit provides limited access to a user’s Calendar database; it does not include everything that would be desired for implementing a full-featured calendar or reminder app, such as adding attendees or accounts.

  • 概覽(At a Glance)

本文檔包含如下幾章,這些內容描述瞭如何在你的應用內集成用戶的日曆和提醒數據:

This document contains the following chapters, which describe how to integrate with users’ calendar and reminder data within your app:

  • “Reading and Writing Calendar Events” explains how to retrieve, create, and modify calendar events.
  • “Reading and Writing Reminders” explains how to retrieve, create, and modify reminders.
  • “Configuring Alarms” explains how to attach alarms to a calendar item.
  • “Creating Recurring Events” explains how to make an event a recurring event.
  • “Observing External Changes to the Calendar Database” explains how to register for notifications regarding external changes to the Calendar database.
  • “Providing Interfaces for Events” explains how to display event view controllers to allow your users to create and edit events.
  • 參見(See Also)

本文檔是下面的示例代碼和參考手冊的配套指南:

  • SimpleEKDemo 是一個使用事件庫中事件的示例代碼工程。
  • Event Kit Framework Reference 提供了一個事件庫 API 的較深入的描述,這些 API 就是一個訪問用戶的日曆數據庫的框架。
  • Event Kit UI Framework Reference 詳細說明了事件庫用戶界面的 API,就是一個 iOS專有的框架,它提供了一些視圖控制器用於顯示和編輯日曆事件。

This document is a companion guide to the following sample code and references:

  • SimpleEKDemo is an example sample code project that utilizes events in Event Kit.
  • Event Kit Framework Reference provides an in-depth description of the Event Kit API, a framework that grants access to a user’s Calendar database.
  • Event Kit UI Framework Reference details the Event Kit UI API, an iOS-specific framework that provides view controllers for displaying and editing calendar events.   
  • 讀寫日曆事件(Reading and Writing Calendar Events )
你可以使用 EKEventStore 類從用戶的日曆數據庫中獲取、創建、編輯和刪除事件。你可以獲取匹配你提供的謂詞的事件自定義的一組事件,或通過唯一標識獲取一個單獨的事件。你獲取到一個事件後,可以使用 EKEvent 類的屬性獲取訪問該事件相關的日曆信息。同樣的,你可以通過設置 EKEvent 類的屬性來修改該事件的日曆信息。

You can fetch, create, edit, and delete events from a user’s Calendar database using the EKEventStore class. You can fetch a custom set of events that match a predicate you provide, or you can fetch an individual event by its unique identifier. After you fetch an event, you can access its associated calendar information with the properties of the EKEvent class. Likewise, you can modify its calendar information by setting the properties of the EKEvent class.   

  • 連接到事件庫(Connecting to the Event Store)    

在 iOS 5 及以後版本系統中,使用默認的初始化器:

On iOS 5 and later, initialize an EKEventStore object with the default initializer:

EKEventStore *store = [[EKEventStore alloc] init];

在 iOS 6 及以後版本,你必須在事件庫初始化後,使用 requestAccessToEntityType:completion: 方法請求使用用戶的日曆數據庫。請求訪問某個實體類型會異步提示用戶允許或禁止你的應用使用他們的日曆信息。你應該處理用戶授權或禁止你的應用訪問權的各種狀況:

On iOS 6 and later, you must request access to use the user’s Calendar database with the requestAccessToEntityType:completion: method after the event store is initialized. Requesting access to an entity type asynchronously prompts the user to allow or deny your app from using their calendar information. You should handle cases for when the user grants and denies access to your app:

[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
    // handle access here
}];

On OS X and later, initialize an EKEventStore object with the designated initializer initWithAccessToEntityTypes::

EKEventStore *store = [[EKEventStore alloc] initWithAccessToEntityTypes:EKEntityMaskEvent];

You do not need to request access to use the user’s Calendar database on OS X, because access is automatically granted.

EKEventStore 對象需要相對較大量的時間來初始化和釋放。因此,你不應該爲每一個事件相關的任務都初始化和釋放事件庫。相反,在你的應用加載時,初始化一個事件庫,然後反覆地使用這一個來確保連接一直可用。

事件庫實例不應該在其它事件開發包相對的對象釋放前被釋放,否則可能發生意想不到的狀態。

An EKEventStore object requires a relatively large amount of time to initialize and release. Consequently, you should not initialize and release a separate event store for each event-related task. Instead, initialize a single event store when your app loads, and use it repeatedly to ensure that your connection is long-lived.

An event store instance must not be released before other Event Kit objects; otherwise, undefined behavior may occur.

 

  • 獲取事件(Retrieving Events)

有兩種方式獲取事件。通過謂詞或搜索查詢獲取,會返回零個或多個與給定查詢匹配的事件。通過唯一標識獲取會返回與給定標識相符的唯一的一個事件。

There are two ways to retrieve events. Fetching via predicates, or search query, will return zero or more events that match a given query. Fetching via unique identifiers will return a single event that corresponds to the given identifier.

注意:從日曆數據庫獲取事件並不一定按時間順序返回。要通過日期排序 EKEvent 對象的數組,可以在數組上調用 sortedArrayUsingSelector: 方法,並提供  compareStartDateWithEvent: 方法的選擇器。

Note:Retrieving events from the Calendar database does not necessarily return events in chronological order. To sort an array of  EKEvent objects by date, call sortedArrayUsingSelector: on the array, providing the selector for the compareStartDateWithEvent: method.

  • 使用謂詞(Using Predicates ) 

通常是要獲得屬於某一日期範圍的事件。 EKEventStore 的 eventsMatchingPredicate: 方法獲取屬於你提供的謂詞中指定的日期範圍的所有事件。

It’s common to fetch events that fall within a date range. The EKEventStore method eventsMatchingPredicate: fetches all events that fall within the date range specified in the predicate you provide. 

列表 1-1 展示瞭如何獲取發生在一天前和當前之後一年之內的所有事件。

Listing 1-1 demonstrates how to fetch all events that occur between one day before and one year after the current date.

注意:儘管  eventsMatchingPredicate: 方法接受一個 NSPredicate類型的參數,但你必須提供一個用 EKEventStore 的方法 predicateForEventsWithStartDate:endDate:calendars: 創建的謂詞。

Note:Although the  eventsMatchingPredicate: method accepts a parameter of type NSPredicate, you must supply a predicate created with the EKEventStore method predicateForEventsWithStartDate:endDate:calendars:.

 

列表 1-1 使用謂詞獲取事件 Listing 1-1 Fetching events with a predicate

 

// 獲取適當的日期(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 值,那麼就是告訴這個方法獲取用戶的所有日曆。

You can specify a subset of calendars to search by passing an array of EKCalendar objects as the calendars parameter of the predicateForEventsWithStartDate:endDate:calendars: method. You can get the user’s calendars from the event store’s calendarsForEntityType: method. Passing nil tells the method to fetch from all of the user’s calendars.

 

因爲方法  eventsMatchingPredicate: 是同步的,而你可能並不想在你的應用主線程中運行它。如果要異步執行的話,那麼使用 dispatch_async 函數或使用一個 NSOperation 對象,就可以在另一個線程中運行該方法了。

Because the eventsMatchingPredicate: method is synchronous, you may not want to run it on your app’s main thread. For asynchronous behavior, run the method on another thread with the dispatch_async function or with an NSOperation object.

  • 使用唯一標識(Using Unique Identifiers )   

如果你之前使用謂詞獲得了一個事件並知道它的唯一標識,那麼你可以使用 EKEventStore 的 eventWithIdentifier: 方法來再次獲取該事件。如果它是一個循環事件,那麼這個方法就會返回第一次出現的該事件。你可以使用屬性 eventIdentifier 獲得事件的唯一標識。

If you know the event’s unique identifier because you fetched it previously with a predicate, you can use the EKEventStore method eventWithIdentifier: to fetch the event. If it is a recurring event, this method will return the first occurrence of the event. You can get an event’s unique identifier with the eventIdentifier property.

  • 創建及編輯事件(Creating and Editing Events)    

注意:如果你正在 iOS上開發,那麼你可以選擇使用事件庫用戶界面框架提供的事件視圖控制器來讓用戶修改事件數據。有關如何使用這些事件視圖控制器的信息,參見“爲事件提供界面。”

使用 事件 EKEvent 的eventWithEventStore: 方法創建一個新的事件。

你可以通過設置一個新的事件或先前從日曆數據庫獲取的事件的對應屬性來編輯事件。你可以編輯的詳細內容包括:

 

Note: If you’re developing on iOS, you have the option of letting users modify event data with the event view controllers provided in the Event Kit UI framework. For information on how to use these event view controllers, see “Providing Interfaces for Events.”

 

Create a new event with the eventWithEventStore: method of the EKEvent class.

 

You can edit the details of a new event or an event you previously fetched from the Calendar database by setting the event’s corresponding properties. Some of the details you can edit include:

 

    • The event’s title with the title property

    • The event’s start and end dates with the startDate and endDate properties

    • The calendar with which the event is associated with the calendar property

    • The alarms associated with the event with the alarms property (see “Configuring Alarms” for more details)

    • The event’s recurrence rule, if it is a repeating event, with the recurrenceRules property (see “Creating Recurring Events” for more details)

  • 保存和移除事件(Saving and Removing Events)    

提示:如果你的應用修改用戶的日曆數據庫,它必須在這之前先從用戶獲得確認。應用在未得到用戶的特定指示的情況下決不可能修改日曆數據庫。

你對事件的修改不是持久化的,直到你保存它們爲止。使用 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 會立即持久保存更改)。

Important: If your app modifies a user’s Calendar database, it must get confirmation from the user before doing so. An app should never modify the Calendar database without specific instruction from the user.

 

Changes you make to an event are not permanent until you save them. Save your changes to the Calendar database with the EKEventStore methodsaveEvent:span:commit:error:. If you want to remove an event from the Calendar database, use the EKEventStore method removeEvent:span:commit:error:. Whether you are saving or removing an event, implementing the respective method automatically syncs your changes with the calendar the event belongs to (CalDAV, Exchange, and so on).

 

If you are saving a recurring event, your changes can apply to all future occurrences of the event by specifying EKSpanFutureEvents for the span parameter of the saveEvent:span:commit:error: method. Likewise, you can remove all future occurrences of an event by specifying EKSpanFutureEvents for the span parameter of theremoveEvent:span:commit:error: method.

Note: If you pass NO to the commit parameter, make sure that you later invoke the commit: method to permanently save your changes.

  • 執行批量事件操作(Performing Batch Operations on Events)    

 

你可以在 EKEventStore 的  enumerateEventsMatchingPredicate:usingBlock: 方法執行給定的謂詞匹配的所有事件上執行同一個操作。你必須爲上述方法使用 EKEventStore 的 predicateForEventsWithStartDate:endDate:calendars: 方法創建謂詞。你提供的操作是 EKEventSearchCallback 類型的塊。

You can perform an operation on all events that match a provided predicate with the EKEventStore method enumerateEventsMatchingPredicate:usingBlock:. You must create the predicate for this method with the EKEventStore method predicateForEventsWithStartDate:endDate:calendars:. The operation you provide is a block of typeEKEventSearchCallback.

 

typedef void (^EKEventSearchCallback)(EKEvent *event, BOOL *stop);

 

塊接收兩個參數(The block is passed two parameters):

 

event

 

當前被操作的事件(The event that is currently being operated on).

 

stop

 

一個布爾值,它決定當前塊返回後 enumerateEventsMatchingPredicate:usingBlock: 方法是否應該停止繼續處理事件。如果是 YES,那麼與該謂詞匹配的任何未處理的事件仍保持未處理狀態。

提示:記住,使用該方法會引起對用戶的日曆數據庫的有效的修改。確認在你向用戶請求批准時,讓用戶清楚地知道你所要執行的操作。

A Boolean value determining whether enumerateEventsMatchingPredicate:usingBlock: should stop processing events when this block returns. If YES, any event that matches the predicate but has not yet been processed will remain unprocessed.

Important: Keep in mind that using this method can result in significant changes to the user’s Calendar database. Make sure the user is fully informed of the actions you are about to perform when you request user confirmation.

 

Because the enumerateEventsMatchingPredicate:usingBlock: method is synchronous, you may not want to run it on your app’s main thread. For asynchronous behavior, run the method on another thread with the dispatch_async function or with an NSOperation object.

 

  • 讀寫提醒(Reading and Writing Reminders)

提醒就是一些可以關聯到特定時間或位置的任務。他們與日曆事件很相似,但可以被標識爲完成並且可以不必跨躍一段確切的時間。

因爲 EKReminder 繼承自 EKCalendarItem ,所以你可以在提醒上執行與在事件上一樣的方法,諸如使用 addAlarm: 方法添加一個鬧鐘,或使用 addRecurrenceRule: 方法設置一個循環規則。

Reminders are tasks that may be tied to a specific time or location. They are similar to calendar events, but can be marked complete and may not necessarily span an exact period of time.

Because EKReminder inherits from EKCalendarItem, you can perform the same methods on a reminder as you would on an event, such as adding an alarm with addAlarm: or setting a recurrence rule with addRecurrenceRule:.

  • 獲取提醒(Retrieving Reminders)    

和事件一樣,你必須先建立與事件庫的連接,才能訪問已存在的提醒。如果你之前沒做過事件庫的連接操作,那麼參見“連接到事件庫”。

要在 OS X 上初始訪問提醒的連接,傳遞的參數不是 EKEntityMaskEvent 而是 EKEntityMaskReminder 。

As with events, you must first establish a connection to the event store to access existing reminders. See “Connecting to the Event Store” if you have not already done so.

To initialize a connection with access to reminders on OS X, pass EKEntityMaskReminder instead of EKEntityMaskEvent.

EKEventStore *store = [[EKEventStore alloc] initWithAccessToEntityTypes:EKEntityMaskReminder];

在 iOS 6 及以後的版本中,事件庫初始化後,你必須使用 requestAccessToEntityType:completion: 請求對用戶日曆數據庫的訪問權。請求某一實體類型的訪問權會提示用戶允許或禁止你的應用使用日曆信息。你應該處理用戶授權或禁止訪問每種情況:

On iOS 6 and later, you must request access to use the user’s Calendar database with the requestAccessToEntityType:completion: method after the event store is initialized. Requesting access to an entity type asynchronously prompts the user to allow or deny your app from using their calendar information. You should handle cases for when the user grants and denies access to your app:

[store requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
    // handle access here
}];

在 OS X 上你不需要請求用戶提醒的訪問權,因爲訪問權是默認授予的(譯者注:iOS 模擬器上也是默認授予的)。

正如搜索事件一樣,也有兩種途徑來獲取提醒。

You do not need to request access for the user’s reminders on OS X, because access is automatically granted.

Just like searching for events, there are two ways to retrieve reminders.

  • 使用謂詞(Using Predicates)    

你可以調用 fetchRemindersMatchingPredicate:completion: 方法來訪問與某一謂詞匹配的多個提醒。傳遞的謂詞可通過如下方法得到:

 

 
你可以給 completion 參數傳一個塊來迭代所有匹配的提醒,如列表 2-1 所示:

You can call fetchRemindersMatchingPredicate:completion: to access multiple reminders that match a predicate. Pass a predicate returned by one of the following methods:

    •  

      predicateForIncompleteRemindersWithDueDateStarting:ending:calendars:

       finds incomplete reminders within an optional time period
    • predicateForCompletedRemindersWithCompletionDateStarting:ending:calendars:

       finds completed reminders within an optional time period
    •  

      predicateForRemindersInCalendars:

        finds all reminders

You can iterate across matched reminders by passing a block to the completion argument, as shown in Listing 2-1.

列表 2-1 使用謂詞獲取提醒

Listing 2-1 Fetching reminders with a predicate

NSPredicate *predicate = [store predicateForRemindersInCalendars:nil];
 
[store fetchRemindersMatchingPredicate:predicate completion:^(NSArray *reminders) {
    for (EKReminder *reminder in reminders) {
        // do something for each reminder
    }
}];

注意:不像通過謂詞獲取事件那樣(參見“使用謂詞”),你可以通過謂詞異步獲取提醒,而無需分派到其它線程。

如果你想要中止通過謂詞獲取的請求,可以調用 cancelFetchRequest: 方法並傳遞之前由 fetchRemindersMatchingPredicate:completion: 方法返回的標識。

Note: Unlike fetching events via predicate (see “Using Predicates”), you can fetch reminders via predicate asynchronously without dispatching to another thread.

If you’d like to abort your fetch request by predicate, call cancelFetchRequest: while passing the identifier as returned by fetchRemindersMatchingPredicate:completion:.

  • 使用唯一標識(Using Unique Identifiers)  

如果你知道一個從先前用謂詞獲取到的提醒的唯一標識,那麼你可以調用 calendarItemWithIdentifier: 實例方法,該方法可以獲取到任何與該標識符匹配的日曆項(提醒或事件),而 eventWithIdentifier: 方法只能獲到事件。

If you know a specific reminder’s unique identifier from previously fetching it with a predicate, you can call the calendarItemWithIdentifier: instance method.calendarItemWithIdentifier: can fetch any calendar item (reminders and events), whereas eventWithIdentifier: fetches only events.

  • 創建及編輯提醒(Creating and Editing Reminders )  

You can create reminders using the reminderWithEventStore: class method. The title and calendar properties are required. The calendar for a reminder is the list with which it is grouped.

Like events, reminders can trigger time-based or location-based alarms to alert the user of a certain task. Read “Configuring Alarms” for more information on how to attach alarms to calendar items.

To associate a start date or due date with a reminder, use the startDateComponents and dueDateComponents properties. To complete a reminder, set the completed property to YES, which automatically sets completionDate to the current date.

  • 保存和移除提醒(Saving and Removing Reminders)   

Important: If your app modifies a user’s Calendar database, it must get confirmation from the user before doing so. An app should never modify the Calendar database without specific instruction from the user.

 

Reminders are saved in a similar fashion to events. To save a reminder to the Calendar database, call the saveReminder:commit:error: method. To remove an event, call the removeReminder:commit:error: method.

 

Remember, the title and calendar properties must explicitly be set before you save your reminder.

Note: Just like when saving or removing events, make sure that if you pass NO to the commit parameter, you later invoke the commit: method to save your changes.

  • 配置鬧鐘(Configuring Alarms)    

An easy way to alert users of their upcoming events is to give them the option of setting alarms for their calendar items. Regardless of the app that’s currently running, alarms come to the foreground as a notification and remind users of the scheduled event. If an alarm is set to a calendar event, the notification comes from the Calendar app; if an alarm is set to a reminder, the notification comes from the Reminders app. Alarms can be time-based, firing at a specified time, or location-based, firing when crossing a geofence (for more information about geofences, see “Setting Geofences”).

Alarms can be applied to both calendar events and reminders.

Note: An alarm is not intended to serve as a UILocalNotification. An alarm requires you to create an event or reminder that is visible in the user’s Calendar or Reminders app. A UILocalNotification is better suited for general purposes that don’t involve the Calendar database.
  • 附加和移除鬧鐘(Attaching and Removing Alarms) 

You can add an alarm to an event with the addAlarm: method. Alarms can be created with an absolute date or with an offset relative to the start date of the event. Alarms created with a relative offset must occur before or at the start date of the event.

In OS X, you can trigger an action alongside the alarm; for example, set:

    • The emailAddress property to send an email

    • The soundName property to play a sound

    • The url property to open a URL

You can remove an alarm from an event with the removeAlarm: method.

  • 設置地理圍欄(Setting Geofences)    

Note: Geofences are supported on both OS X and iOS, but they are more effective on mobile devices.

 

A geofence is a virtual border surrounding a geographic location that, when crossed, can trigger an alarm for an event. Geofences are a useful way to remind users of tasks they need to do when entering or exiting a certain region. For example, when a user leaves his workplace, an alarm can fire that reminds him to stop by the grocery store. As a developer, you have control over specifying the latitude and longitude of the center, as well as the radius of the geofence.

 

Configure a geofence for an event by creating an alarm and setting its structured location and proximity. Call the locationWithTitle: method to create a structured location. To set longitude and latitude coordinates, pass a CLLocation to the geoLocation property of the structured location returned. A value of 0 for the radius property will use the system’s default radius; to choose a radius of your own, specify a value in meters.

 

While geofence-enabled alarms can be applied to events, they are more practical for reminders.

  • 創建循環事件(Creating Recurring Events) 

Recurring events repeat over a specified interval of time. To make an event a recurring event, assign it a recurrence rule, which describes when the event occurs. Recurrence rules are represented by instances of the EKRecurrenceRule class.

Recurrence is applicable to both calendar events and reminders. Unlike with recurring events, only the first incomplete reminder of a recurring set is obtainable. This is true with Event Kit as well as the Reminders app. When the reminder is completed, the next reminder in the recurrence set becomes available.

  • 使用基本規則(Using Basic Rules) 

You can create a recurrence rule with a simple daily, weekly, monthly, or yearly pattern using the initRecurrenceWithFrequency:interval:end: method. You provide three values to this method:

    • The recurrence frequency

       . This is a value of type EKRecurrenceFrequency that indicates whether the recurrence rule is daily, weekly, monthly, or yearly.
    • The recurrence interval

       . This is an integer greater than 0 that specifies how often a pattern repeats. For example, if the recurrence rule is a weekly recurrence rule and its interval is 1, then the pattern repeats every week. If the recurrence rule is a monthly recurrence rule and its interval is 3, then the pattern repeats every three months.
    • The recurrence end

       . This optional parameter is an instance of the EKRecurrenceEnd class, which indicates when the recurrence rule ends. The recurrence end can be based on a specific end date or on an amount of occurrences.
If you don’t want to specify an end for the recurrence rule, pass nil.
  • 使用複雜的規則(Using Complex Rules)  

You can create a recurrence rule with a complex pattern using the 

initRecurrenceWithFrequency:interval:daysOfTheWeek:daysOfTheMonth:monthsOfTheYear:weeksOfTheYear:daysOfTheYear:setPositions:end: 

method. As you do for a basic recurrence rule, you provide a frequency, an interval, and an optional end for the recurring event. In addition, you can provide a combination of optional values describing a custom rule, as listed in Table 4-1.

Table 4-1  Complex recurrence rule breakdown

Parameter name

Accepted values

Can be combined with

Example

days

The days of the week on which the event occurs.

An array ofEKRecurrenceDayOfWeek objects.

All recurrence rules except for daily recurrence rules.

An array containing EKTuesday and EKFriday objects will create a recurrence that occurs every Tuesday and Friday.

monthDays

The days of the month on which the event occurs.

An array of nonzero NSNumberobjects ranging from –31 to 31. Negative values indicate counting backward from the end of the month.

Monthly recurrence rules only.

An array containing the values 1 and –1 will create a recurrence that occurs on the first and last day of every month.

months

The months of the year in which the event occurs.

An array of NSNumber objects with values ranging from 1 to 12, corresponding to Gregorian calendar months.

Yearly recurrence rules only.

If your originating event occurs on January 10, you can provide an array containing the values 1 and 2 to create a recurrence that occurs every January 10 and February 10.

weeksOfTheYear

The weeks of the year in which the event occurs.

An array of nonzero NSNumberobjects ranging from –53 to 53. Negative values indicate counting backward from the end of the year.

Yearly recurrence rules only.

If your originating event occurs on a Wednesday, you can provide an array containing the values 1 and –1 to create a recurrence that occurs on the Wednesday of the first and last weeks of every year. If a specified week does not contain a Wednesday in the current year, as can be the case for the first or last week of a year, the event does not occur.

daysOfTheYear

The days of the year on which the event occurs.

An array of nonzero NSNumberobjects ranging from –366 to 366. Negative values indicate counting backward from the end of the year.

Yearly recurrence rules only.

You can provide an array containing the values 1 and –1 to create a recurrence that occurs on the first and last day of every year.

setPositions

The occurrences to include in the recurrence rule. This filter is applied to the set of occurrences determined from the other parameters you provide.

An array of nonzero NSNumberobjects ranging from –366 to 366. Negative values indicate counting backward from the end of the list of occurrences.

All recurrence rules except for daily recurrence rules.

If you provide an array containing the values 1 and –1 to a yearly recurrence rule that has specified Monday through Friday as its value for days of the week, the recurrence occurs only on the first and last weekday of every year.

You can provide values for any number of the parameters in Table 4-1. Parameters that don’t apply to a particular recurrence rule are ignored. If you provide a value for more than one of the above parameters, the recurrence occurs only on days that apply to all provided values.

Once you have created a recurrence rule, you can apply it to a calendar event or reminder with the addRecurrenceRule: instance method of EKCalendarItem.

  • 監視日曆數據庫的外部更改(Observing External Changes to the Calendar Database) 

It’s possible for another process or app to modify the Calendar database while your app is running. If your app fetches calendar events or reminders, you should register to be notified about changes to the Calendar database. By doing so, you ensure that the calendar and reminder information you display to the user is current.

  • 註冊通知(Registering for Notifications)

An EKEventStore object posts an EKEventStoreChangedNotification notification whenever it detects changes to the Calendar database. Register for this notification if your app handles event or reminder data.

The following code registers for the EKEventStoreChangedNotification notification, as shown in Listing 5-1.

Listing 5-1 The EKEventStoreChangedNotification notification

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(storeChanged:)
                                             name:EKEventStoreChangedNotification
                                           object:eventStore];
  • 響應通知(Responding to Notifications)    

When you receive an EKEventStoreChangedNotification notification, it’s possible that objects you’ve fetched—such as an EKEventEKReminder, or EKCalendar, among others—have changed. The effect of these changes depends on whether an event was added, modified, or deleted.

    • If an event was added, it does not affect any of your previously fetched events or reminders, but the added event may fall within the date range of events you are displaying to the user.

    • If an event was modified or deleted, properties of EKEvent and EKReminder objects representing that event may become out of date.

Because your local data is often invalidated or incomplete when a change occurs in the Calendar database, you should refetch your current date range of events whenever you receive an EKEventStoreChangedNotification notification. If you are currently modifying an event and you do not want to refetch it unless it is absolutely necessary to do so, you can call the refresh method on the event. If the method returns YES, you can continue to use the event; otherwise, you need to refetch it.

Note: Events being modified in an event view controller with Event Kit UI for iOS are updated automatically when a change occurs in the Calendar database. For a more in-depth look at Event Kit UI, read the next chapter, “Providing Interfaces for Events.”
  • 提供事件界面(Providing Interfaces for Events)  
Important: The Event Kit UI framework, as referenced by this chapter, is available for iOS only. If you are developing for OS X, you are responsible for constructing your own event view controllers; for more information, read NSViewController Class Reference.

 

The Event Kit UI framework provides two types of view controllers for manipulating events:

 

  • 顯示事件數據(Displaying Event Data) 

To use the EKEventViewController class, you must have an existing event you obtained from an event store. You need to set the event property and any other display options before presenting this type of view controller. Listing 6-1 shows how to create an event view controller and add it to a navigation controller, assuming myEvent already exists. If you don’t allow the user to edit the event, set the allowsEditing property to NO.

Listing 6-1 Editing an existing event

EKEventViewController *eventViewController = [[EKEventViewController alloc] init];
eventViewController.event = myEvent;
eventViewController.allowsEditing = YES;
navigationController = [[UINavigationController alloc] initWithRootViewController:eventViewController];

You need to assign a delegate to an event view controller to receive a notification when the user finishes viewing the event. The delegate conforms to the EKEventViewDelegateprotocol and must implement the eventViewController:didCompleteWithAction: method.

  • 修改事件數據(Modifying Event Data)  

To allow the user to create, edit, or delete events, use the EKEventEditViewController class and the EKEventEditViewDelegate protocol. You create an event edit view controller similar to an event view controller, except you must set the eventStore property (setting the event property is optional).

    • If the event property is nil when you present the view controller, the user creates a new event in the default calendar and saves it to the specified event store.

    • If the event property is not nil, the user edits an existing event. The event must reside in the specified event store—otherwise, an exception is raised.

Instances of the EKEventEditViewController class are designed to be presented modally, as shown in Listing 6-2. In this code fragment, self is the top view controller of a navigation controller. For details on modal view controllers, read “Presenting a View Controller Modally” in View Controller Programming Guide for iOS.

Listing 6-2 Presenting an event edit view controller modally

EKEventEditViewController* controller = [[EKEventEditViewController alloc] init];
controller.eventStore = myEventStore;
controller.editViewDelegate = self;
[self presentModalViewController:controller animated:YES];

You must also specify a delegate to receive notification when the user finishes editing the event. The delegate conforms to the EKEventEditViewDelegate protocol and must implement the eventEditViewController:didCompleteWithAction: method to dismiss the modal view controller, as shown in Listing 6-3. In general, the object that presents a view controller modally is responsible for dismissing it.

Listing 6-3 The delegate dismisses the modal view

- (void)eventEditViewController:(EKEventEditViewController *)controller
          didCompleteWithAction:(EKEventEditViewAction)action
{
    [self dismissModalViewControllerAnimated:YES];
}

The delegate is also passed the action the user took when finishing the edit. The user can either cancel the changes, save the event, or delete the event. If you need to execute more code after the user dismisses the modal view, implement the eventEditViewController:didCompleteWithAction: delegate method.

  • 文檔修訂歷史(Document Revision History)   

This table describes the changes to Calendar and Reminders Programming Guide.

Date Notes
2012-07-17 Updated to support OS X Mountain Lion.
2010-09-22 Made improvements throughout.
2010-08-03 Added a link to the SimpleEKDemo sample code.
2010-04-29 New document that explains how to access calendar data in iOS with the Event Kit framework.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章