關於Calendar和Reminder

關於Calendar和Reminder(日曆和提醒)編程指南  

2012-08-28 18:02:20|  分類: iOS|舉報|字號 訂閱

Event Kit框架使你能訪問用戶的Calendar.app和Reminders.app信息。雖然這是兩個不同的app,但是他們使用相同的框架處理數據。類似地,存儲這些數據的數據庫,被稱爲日曆數據庫,持有calendar和reminder信息。
Event Kit除了允許你檢索用戶已經存在的calendar和reminder數據外,還允許你創建新的事件和提醒。另外,還允許你修改和刪除事件和提醒。更高級的任務,例如添加警報或指定重複發生的事件,也可以。

一、Reading and Writing Calendar Events:
使用EKEventStore類來獲取、創建、修改和刪除事件,使用EKEvent類來表示事件。
1、連接到Event Store:
實例化EKEventStore對象:
EKEventStore *store=[[EKEventStore alloc] initWithAccessToEntityTypes:EKEntityMaskEvent];
一個EKEventStore對象需要一段明顯的時間來初始化和釋放。因此,你不應該爲每個事件相關的任務都初始化和釋放一個單獨的event store。取而代之的,在你的應用加載時,初始化一個event store,並且重複使用它。
event store必須不能在其它的Event Kit對象之前被release,否則未定義的行爲可能發生。

2、檢索事件
有2個方法檢索事件。使用predicate或search query,將返回0或多個事件來匹配給定的查詢條件。使用唯一標識符將返回一個單獨的事件。
注意:檢索的事件不一定按照年代排序。要通過日期排序一組EKEvent對象,調用sortedArrayUsingSelector:方法,並使用selector爲compareStartDateWithEvent:方法。

3、使用Predicates:
EKEventStore的方法eventsMatchingPredicate:檢索所有的在你提供的日期範圍內的事件。

注意:雖然eventsMatchingPredicate:方法接收NSPredicate類型的參數,但是這個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];

你可以爲predicateForEventsWithStartDate:endDate:calendars:方法指定一組EKCalendar對象作爲calendars的參數。你可以使用evnet store的calendarsForEntityType:方法 獲得用戶的calendars.傳遞nil值告訴方法從用戶所有的calendars中獲取數據。

因爲eventsMatchingPredicate:方法是同步的,所以應該在另外的線程執行。

4、使用唯一標識符
使用EKEventStore的方法eventWithIdentifier:來獲取事件。如果這是一個重複發生的事件,這個方法將返回第一個將要發生的事件。你可以通過EKEvent的eventIdentifier屬性來獲得唯一標識符。

5、創建和修改事件
使用EKEvent類的eventWithEventStore:方法創建一個新的事件
你可以編輯新事件或你之前獲得的事件的細節.包括:
1)title屬性
2)startDate和endDate屬性
3)calendar屬性:事件關聯的日曆
4)alarm屬性
5)recurrenceRules屬性:默認是不重複的


6、保存和移除事件
如果你要修改用戶的日曆數據庫,必須得到用戶的確認。
你對事件所做的更改在你保存它們之前不會永久有效。使用EKEventStore的方法saveEvent:span:commit:error:方法來保存事件。使用removeEvent:span:commit:error:來移除事件。
如果你正在保存一個重複發生的事件,你的更改可以通過指定span參數爲EKSpanFutureEvents來將其應用到所有將來發生的事件。同樣的,通過指定span參數爲EKSpanFutureEvents,你可以移除所有將來發生的事件。

注意:如果你傳遞NO給commit參數,確保你之後調用commit:方法來永久保存你的更改。

7、執行事件批處理操作:
EKEventStore的enumerateEventsMatchingPredicate:usingBlock:方法允許你執行所有匹配Predicate的事件的批處理操作。你提供的operation是一個block,其類型爲EKEventSearchCallback。
typedef void (^EKEventSearchCallback)(EKEvent *event,BOOL *stop)
這個方法同樣也會消耗一段時間,建議在另外的線程執行。

二、Reading and Writing Reminders:
Reminder是綁定到特定時間或位置的任務。他們和Calendar事件類似,但是可以被標記爲完成,並且可能不需要span一個精確的時間週期。
因爲EKReminder繼承自EKCalendarItem,因此你可以在一個reminder上執行如同你在事件上執行的相同的方法,例如addAlarm:或通過addRecurrenceRule:來設置recurrence規則.
1、檢索Reminders:
要訪問Reminders,還是實例化EVEventStore,傳遞EKEntityMaskReminder 而不是EKEntityMaskEvent
EKEventStore *store=[[EKEventStore alloc] initWithAccessToEntityTypes:EKEntityMaskReminder];

1)使用Predicate檢索:
你可以調用fetchRemindersMatchingPredicate:completion:方法。傳遞的Predicate使用下面方法創建:
a)predicateForInCompleteRemindersWithDueDateStarting:ending:calendars:來查找未完成的reminders
b)predicateForCompleteRemindersWithCompletionDateStarting:ending:calendars:來查找已經完成的reminders
c)predicateForRemindersInCalendars:來查找所有的reminders

你可以在completion block中遍歷找到的EKReminder對象
例子:
NSPredicate *predicate = [store predicateForRemindersInCalendars:nil];
 
[store fetchRemindersMatchingPredicate:predicate completion:^(NSArray *reminders) {
    for (EKReminder *reminder in reminders) {
        // do something for each reminder
    }
}];

2)使用唯一標識符
calendarItemWithIdentifier:方法可以查找所有的calendar item(包括Reminder和Events),而eventWithIdentifier:只查詢events。

2、創建和編輯Reminders:
你可以使用EKEventStore的reminderWithEventStore:類方法來創建reminder,title和calendar屬性是必須的。
startDateComponents和dueDateComponents屬性。
要完成一個reminder,設置completed屬性爲YES,這回自動地設置completionDate爲當前日期。

3、保存和移除Reminders:
這也需要用戶確認。
saveReminder:commit:error:方法和removeReminder:commit:error:方法。
記住,在你保存你的reminder之前,必須設置title和calendar屬性。

三、配置Alarms
不管當前運行的是哪個程序,alarm會作爲一個通知來到前臺來提醒用戶。如果一個alarm被設置到一個日曆事件中,那麼通知來自於Calendar.app;如果alarm被設置到一個reminder中,那麼通知來自於Reminders.app。Alarms可以是基於時間的,在某個特定的時間發射,或基於位置的,當經過某個迪蘭圍欄(geofence)時發射。
事件和Reminder都可以設置alarm。

1、Attaching and Removing Alarms:
addAlarm:方法。Alarm可以使用絕對日期和相對日期創建。
removeAlarm:方法來移除。
在OS X中,你可以觸發一個alarm動作。例如,設置:
1)emailAddress屬性來發送一封郵件
2)soundName屬性來播放一個聲音
3)url屬性來打開一個URL。

2、設置Geofences:
注意:OS X和iOS都支持Geofence,但是他們在移動設備上更有效。
一個geofence是一個虛擬的包圍一個地理位置的border,當穿越它時,可以觸發一個事件的alarm。作爲一個開發者,你需要控制center的緯度和經度,和geofence的半徑。
調用locationWithTItle:方法來創建一個結構化的location。要設置經度和緯度 coordinates,傳遞一個CLLocation給結構化的location的geoLocation屬性。radius屬性爲0表示系統默認的半徑;單位爲米。
這對Reminders很有實際意義。

四、創建重複發生的事件:
重複發生的規則使用EKRecurrenceRule類來表示。
calendar event和reminder都可以使用Recurrence。

1、使用基本的規則:
你可以創建一個簡單recurrence規則,使用daily、weekly、monthly或yearly,使用initRecurrenceWithFrequency:interval:end:方法。你可以在這個方法中提供3個值:
1)recurrence frequency:這個值是EKRecurrenceFrequency類型,指示recurrence是daily、weekly、monthly或yearly.
2)recurrence interval: 這是一個大於0的整數,來制定重複的間隔。例如,如果recurrence rule是weekly,並且recurrence interval是1,然後重複模式爲每星期都重複。如果recurrence interval是3,那麼是每3個星期重複一次。
3)recurrence end: 這是個可選參數,是一個EKRecurrenceEnd類的對象,它指示recurrence rules何時終止。

2、使用複合規則:
使用
initRecurrenceWithFrequency:interval:daysOfTheWeek:daysOfTheMonth:monthsOfTheYear:weeksOfTheYear::daysOfTheYear:setPostions:end:
方法。在這個方法裏,你可以提供額外的可選值的組合來描述一個特定的規則:

days   爲 一組 EKRecurrenceDayOfWeek對象,      可以和除了daily recurrence以外的rule組合  ,例子:一個包含EKTuesday和EKFriday對象的array將創建一個每個週二和週五發生的規則。

monthDays  爲一組非0的NSNumber對象,從-31到31.負值表示從當前月的結尾向前計算,可以和Monthly 規則組合,例子:一個包含1和-1的array,將創建每個月第一天和最後一天發生的規則。

months 爲一組1到12的NSNumber對象,對應格里高裏日曆的月份,可以和Yearly組合。

weeksOfTheYear 爲一組非0的NSNumber對象,從-53到53。負值表示從一年的最後一個禮拜向前計算。可以和Yearly組合。

daysOfTheYear 爲一組非0NSNumber對象,從-366到366. 可以和Yearly組合

setPositions: 爲一組非0NSNumber對象,從-366到366.負值表示反向計算。可以和除了daily規則之外的所有規則組合。例子:如果你提供了一個包含1和-1的array到一個yearly規則,並且指定了週一到週五的daysOfTheWeek,那麼重複發生只在第一週和最後一週。也就是說這個參數過濾其它規則的過濾器。

你可以提供任意的number參數值,不能應用的參數會被忽略。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.

一旦你創建了一個recurrence rule,你可以應用它到事件和reminder上,通過EKCalendarItem的addRecurrenceRule:實例方法。

五、觀察外部的日曆數據庫的更改:
1、註冊通知:
一個EKEventStore對象發佈EKEventStoreChangedNotification通知。
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(storeChanged:)
                                             name:EKEventStoreChangedNotification
                                           object:eventStore];

2、響應通知:
當你收到一個EKEventStoreChangedNotification通知時,可能你已經獲取到的對象--例如EKEvent、EKReminder或EKCalendar--已經改變了。這些更改的效果基於事件是添加、修改還是刪除。
1)如果一個event被添加了。這不影響你現有的獲取到的事件和reminder,但是新添加的event可能不會顯示給用戶(因爲你是在新添加的event之前獲取的數據)。
2)如果event被修改了或刪除了,表示那個event的EKEvent和EKReminder對象的屬性將變得過期。

因爲在你收到EKEventStoreChangedNotification通知時,也就是在日曆數據庫發生更改時,你的本地數據經常被無效或未完成,所以你應該重新獲取你當前日期範圍的events。如果你正在修改一個event並且你不想重新獲取它除非絕對需要這樣做,你可以調用日曆事件的refresh方法。如果這個方法返回YES,你可以繼續使用這個日曆事件,否則,你應該重新獲取它。

六、提供事件的Interface
注意:這章討論的Event Kit UI 框架只適用於iOS,在OS X中,你需要自己創建界面。

Event Kit UI 框架提供了兩種類型的View Controller來管理事件:
1)EKEventViewController: 來顯示一個已經存在的事件
2)EKEventEditViewController: 來創建、修改和刪除事件


1、顯示Event數據:
使用EKEventViewController。你需要在顯示view controller之前,設置event屬性,和其它顯示屬性。例子:
    EKEventViewController *eventViewController = [[EKEventViewController alloc] init];
    eventViewController.event = myEvent;
    eventViewController.allowsEditing = YES;
    navigationController = [[UINavigationController alloc] initWithRootViewController:eventViewController];

你需要指定一個delegate給event view controller,在用戶完成查看事件時接收通知。代理遵循EKEventViewDelegate協議並且必須實現eventViewController:didCompleteWithAction:方法。

2、修改Event數據:
使用EKEventEditViewController和EKEventEditViewDelegate協議。像創建EKEventViewController一樣創建EKEventEditViewController,除了你必須設置eventStore屬性(設置event屬性爲可選的)
1)如果event屬性爲nil,那麼用戶創建一個新的event,在默認的calendar並保存它到指定的event store。
2)如果event屬性不爲nil,那麼用戶編輯這個event。這個event必須存在於指定的event store。否則發生異常。
例子:
    EKEventEditViewController* controller = [[EKEventEditViewController alloc] init];
    controller.eventStore = myEventStore;
    controller.editViewDelegate = self;
    [self presentModalViewController:controller animated:YES];

代理函數:eventEditViewController:didCompleteWithAction: 一般在這個函數中取消modal的view controller。
action參數指定用戶是cancel還是save,還是delete。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章