発表:リマインダーの繰り返しを自由に設定する (Mac)(2/08)
アプリで設定できるものでは足らないので、EventKit経由で自由に繰り返しを設定するよ、という話。
リマインダー
というもの。この繰り返しが、アプリ上では
- 毎日
- 毎週
- 隔週(2週間)
- 毎月
- 毎年
の5種類のうちから選ぶようになっていて、それ以外の期間が設定できない。もしかしたらそういう操作があるのかもしれないけど、みつからなかった。
EventKitとリマインダー
以前の勉強会で他の人がEventKitの発表をしていて、「カレンダーやリマインダーを操作できる」という話があったのを思い出したので、それを試してみることに。
Mac Developer Libraryの"Calendar and Reminders Programming Guide "をざっと読むと、"EKRecurrenceRule"が繰り返しをあらわすクラスのようだ。EKRecurrenceRuleのプロパティでは、繰り返し期間は
- frequency: enum EKRecurrenceFrequencyであらわされる{年,月,週,日}の単位
- intercal: 期間の数。数値。
の2つの組み合わせで表現されており、任意の期間が指定できそうだ。また、
- daysOfTheWeek: 一週間のうちの曜日。複数指定もあり。
などずいぶん込み入った繰り返しも表現可能なようだ。
実際のところAPI上は可能でも、その繰り返しを受け入れるか、その繰り返しで次回の期限が設定されるか、はわからないところ。実際に試して確認したほうがよさそう。
動作確認の前にちょっとEventKitの構成を簡単に説明。リマインダーまわりは次のような構造になっている。
- EKEventStore - リマインダー or イベントを保存しているもの。
- EKCalendar - "ビジネス"、"買い物"などの種類。
- EKReminder - 個々のリマインダー。繰り返しの情報はこいつが持っている。
ほぼアプリみたままね。
実際に繰り返しを持ったリマインダーを登録してみる
いちいちアプリをつくるのもめんどうなので、RubyCocoaとirbで直接操作することに。以下がデモのあんちょこ。実行時に「ターミナル.app」にリマインダーへのアクセス許可が必要なことに注意。(デモのとき無効にしてたの忘れてて、あれっ?となってしまった。。)
require 'osx/cocoa' include OSX require_framework 'EventKit' # リマインダーのストア store = EKEventStore.alloc.initWithAccessToEntityTypes(EKEntityTypeReminder) # 追加するリマインダーをタイトルからとってくる calendars = store.calendarsForEntityType(EKEntityTypeReminder) calendar = calendars.find {|cal| cal.title == "テストだよ!"} # 環境によってタイトルは要調整 # 新しいリマインダーを作成する reminder = EKReminder.reminderWithEventStore(store) reminder.title = "3週間ごとに実行する!" # 期限の日付を用意する due_date = NSDateComponents.alloc.init due_date.year = 2014; due_date.month = 2; due_date.day = 8 due_date.hour = 18; due_date.minute = 30 reminder.dueDateComponents = due_date # 繰り返しルール(3週間ごと)を作成する rule = EKRecurrenceRule.alloc.initRecurrenceWithFrequency_interval_end(EKRecurrenceFrequencyWeekly, 3, nil) reminder.addRecurrenceRule(rule) # 保存する result, err = store.saveReminder_commit_error(reminder, true) # おおっとエラー。メッセージをみてみましょう。 err.localizedDescription # カレンダーの指定を忘れてましたね reminder.calendar = calendar result, err = store.saveReminder_commit_error(reminder, true) ## => リマインダーに保存されていること、指定の3週間ごとに実行されることを確認
これで作成したリマインダーを「完了」→「次の期限を確認」として、実際に3週間ごとの繰り返しで動作していることを確認した。めでたしめでたし。
もっと複雑な繰り返しを試してみる
"月2回の締め日(15, 月末)"。daysOfTheMonthでは負の値は末日からの日にちになるので、"-1"は月末になる。
rule1 = EKRecurrenceRule.alloc.initRecurrenceWithFrequency_\ interval_daysOfTheWeek_daysOfTheMonth_monthsOfTheYear_\ weeksOfTheYear_daysOfTheYear_setPositions_end_(EKRecurrenceFrequencyMonthly, 1, nil, [15, -1], nil, nil, nil, nil, nil)
"毎月第1、第3水曜日"。EKRecurrenceDayOfWeekを使うと「指定期間のn番目の指定曜日」が指定できる。次のようにすると、月々の第1水曜と第3水曜を対象にできる。
days_of_week = [EKRecurrenceDayOfWeek.dayOfWeek_weekNumber(4, 1), EKRecurrenceDayOfWeek.dayOfWeek_weekNumber(4, 3)] rule2 = EKRecurrenceRule.alloc.initRecurrenceWithFrequency_\ interval_daysOfTheWeek_daysOfTheMonth_monthsOfTheYear_\ weeksOfTheYear_daysOfTheYear_setPositions_end_(EKRecurrenceFrequencyMonthly, 1, days_of_week, nil, nil, nil, nil, nil, nil)
それぞれ上記の繰り返しを適用したリマインダーを作成し、実際に意図したとおりに動作することを確認した。
まとめ
EventKitのEKRecurrenceRuleではかなり自由に繰り返し期間を設定できる。ただアプリ上は「カスタムの期間」となってしまい、登録後に設定がよくわからなくなってしまうのがちょっと残念。