Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2006-113
$eventId
ID of event: wwdc2006
$eventContentId
ID of session without event part: 113
$eventShortId
Shortened ID of event: wwdc06
$year
Year of session: 2006
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC06 • Session 113

Integrating with iCal

Application Technologies • 22:54

New Leopard Calendaring technologies offer exciting ways to programmatically integrate with the iCal API to obtain, edit, and create iCal's event and task information. Whether you want to simply query upcoming events or use iCal to store all your calendaring data, the CalendarStore framework empowers developers to easily add calendaring functionality. In this session we will explore the APIs in the CalendarStore framework and demonstrate how easy it is to use.

Speakers: Red Dutta, Matt DiMaggio

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Thank you and good afternoon. This is the Integrating with iCal session and I'm Red from the iCal team and just want to thank you all for coming on down. So the team has been very busy working on a new framework for all of you guys. You saw it in action Monday morning with mail to-dos. You could see it takes full advantage of our to-do support with due dates, alarms, priorities, putting in what calendar you want. So it reads and writes to-dos.

As you may have seen on the seed or other demos, there's a new widget that used to be called the calendar widget, which is now the iCal widget. And it takes advantage of the framework to use events. So you've got mail using it for to-dos and the widget using it for events. And we'd like to see a lot more applications from all of you guys coming on and using it. And these are just kind of maybe some wishful thinking possibilities.

So you're going to hear this a few times that it's easy. I'm saying it now. You're going to hear my teammate Matt say it a few times. We've taken the time to do all the heavy lifting as far as the data storage is concerned and recurrence expansion. So like the widget, if you're interested in just a particular day's worth of events, We'll do all the figuring out of what events really exist today. Thanksgiving, which is the fourth Thursday of every November, does it fit inside the pattern or not? There's hundreds of lines of recurrence expansion and valuation. We're doing that. The data storage of how you store events that occur on the first and 15th of every month.

We'll do all that heavy lifting for you. You all should focus on making your apps great and figuring out ways to interoperate with iCal. The stuff you have in your app will show up in iCal. And then if you want to read it, it'll be there vice versa also.

Now, what if you're already accessing iCal through AppleScript or Sync Services? Well, don't worry about it. We're not touching it. It's still there. It'll still work. And if you're asking yourself, so which way should I get at the data? Should it be through AppleScript or Sync Services or the new framework? I'd ask you to think about that.

I'd ask you to think about the Address Book framework a little bit because it actually has all three methods, comparable methods of interacting with it. And you have to think about your data interaction and how you want to really interact with Address Book. The same thing would be true about Calendar, the Calendar Store framework.

So one other thing. This is a very big, large, extensive framework. And we believe we've done a really good job. We know we can make it better. And we want your feedback. So tomorrow at Mac OS X Lab C, we're all going to be there at 3:30, and we'd like you to come down, bring your PowerBooks, bring your code, try it out, see what works well, see what needs a little polish, come and just meet us and talk to us.

Tell us what you need, what you've been doing with iCal, and see how we can try and make things work as best as we can for all of you guys. So without further ado, I'd like to introduce Matt DiMaggio. And he'll go in. into the framework in detail. Thank you.

Thanks, Red. So my name is Matt. I'm excited to be here to talk to you guys about the CalendarStore framework, which is, as it says up there, a new way to access iCal's data. So just to give you a kind of road map of what we'll be talking about today, first I'll go over reading calendar data and look at all the various classes in the API. I'll move on to the notification model and finally conclude with writing calendar data, going into things you need to be aware of when doing that.

So who is this API for? Well, anybody who wants to access iCal's data. This could be reading and writing data, as Mail does, or just sharing data, like the new iCal widget. I think the easiest way to understand the classes in this framework is by correlating them to things that you're already familiar with in iCal. So you'll notice in the list of calendars there, those things are all represented as Cal calendars. Events are Cal events. To-dos are Cal tasks, and so on.

And what we'll be doing throughout this talk is kind of giving you an example of how to go from here, where the data is in iCal, to here, where the data is in your application. So the first thing we'll talk about, the first class, is Cal CalendarStore. This really is where it all starts.

I think the easiest way to-- or one thing that I remind you of is AB Address Book. This is the class where you'll be getting access to the three main data types in the framework. That's calendars, events, and to-dos. And if somebody's looking at that and thinking, to-dos, hmm, there shouldn't be an apostrophe there. Well.

We talked about that and talked about maybe writing it as to-dos without an apostrophe. That doesn't look right, so maybe there's not a space. We actually spent an inordinate amount of time on the team going over how this should be spelled and written in documentation. And so what you'll find within the API itself is we do not refer to to-dos.

Instead, we call everything tasks. So... I'll use the two terms interchangeably while I'm up here, but they're the same. To do an iCal is a task in the API. So as I said, Cal CalendarStore is your main place to access data. It contains all the information that you'll see in iCal.

And here are the principal methods to access that data. So default CalendarStore is a class method that gives you access to an instance of the CalendarStore. And then you can make calls on the CalendarStore to get a full list of calendars or to get-- oops, there you go-- and that'll return an array of Cal calendars. An array of events using a predicate, which we'll talk about, that returns an array of cal events. And of course, tasks also using a predicate.

So I'll kind of be building this diagram as I go through, just another way to kind of understand the classes and their relationship with each other. That's the Cal Calendar Store. The first data class that we're going to look at is Cal Calendar. Again, this is exactly the same thing we would be seeing in iCal's UI.

So here are the main methods on Cal Calendar. There's the color, which is the same as the color that shows up in iCal. And the title, which is again the title. And there are two more methods here that are also pretty useful. IsEditable would tell you whether or not the calendar-- whether or not you can make changes to events and tasks that appear on the calendar.

So example of events that the user can't make changes to and that you won't be able to make changes to using the API are things that appear on a subscribe calendar, on iCal's birthday calendar, or on one of the CalDaf calendars, which you probably heard about in earlier sessions. And finally, a UID in case you need to store a reference to that calendar for some point in the future. All right. This is the first data class. The second one is CalEvent.

Now CalEvent is actually a subclass of CalCalendarItem. This is the only inheritance we have in the framework. And CalCalendarItem contains things that are relevant to events and tasks, or to-dos. Those things include the title, the calendar, which is returned as a CalCalendar, the class we just reviewed, Alarms, which is an array of CalAlarms, which we'll look at later, and the URL and notes that are associated with a given event.

and CalEvent itself has event specific data. There's the location, whether or not the event is all day. The rule is stored as a CalRecurrence rule, yet another class in the framework. And finally, attendees. That's an array of attendees. Those are represented as CalAttendees, the final class we'll be looking at.

So using those three classes, Cal Calendar Store, Cal Calendars, and Cal Events, we actually have enough information to show the events as they appear here in the iCal widget. Now one other point I want to discuss before we look at some sample code is that the events you see here represented in the widget aren't all of the events that are in the user's calendar. These are events that begin on a specific day. And you're going to define that using the API with a start date and an end date. So there's two pieces of information you need.

The third one is a list of calendars. And here in the widget, we're actually showing events from all the calendars. But in your app, you'll be able to show events and tasks from only certain calendars, just like iCal does. So we take those three pieces of information, the calendars, the start date, and the end date, and roll them up into a single NS predicate that you'll be able to use to query for a list of events. Here is some sample code. Start off by getting an instance of the Cal CalendarStore. and kind of create a predicate using the three pieces of information I just discussed: the start date, end date, and a list of calendars. And then get all the events. That's it.

So if all you want to do is look at the events that are in the iCal widget like you saw there, then we're done. You can actually get on to the Safari and WebKit session going on down the hall and get some more information. For the grizzled veterans that are looking for a more thorough discussion of the API, we'll move on to the next data class, which is CalTask.

All right, as I mentioned before, CalTask is a subclass of CalCalendarItem. So it has all the same things that CalCalendarItem has for CalEvents. And these are calendars, the URLs, et cetera. And then CalTask itself only has a few specific fields. There's a Boolean for whether or not it's completed. An enumerated type, CalPriority, for how high the priority of the event is. And a due date, stored as an NSDate.

So when we talked about events, there were three parameters that we used to kind of describe the events that we wanted. The start date, the end date, and the list of calendars. Now with tasks it's a little different. We're still using an array of calendars, but instead of a start date and end date, you'll use completed, whether or not it's completed, and when it was completed. And the due date, again, whether or not it has a due date and when that due date is.

The sample code is very similar. Get a copy of the CalendarStore, create a predicate using the array of calendars as discussed before, and then ask for the tasks. Again, that's it. Three lines of code. Now because the due date and the completed date are different and a little more complicated than with events, the predicates look a little different. And you'll notice that when you look at the predicate extensions in Cal CalendarStore. There's more ways to query for tasks and a few more predicates.

All right, so these are the three main data types that you'll be accessing: CalCalendars, CalEvents, and Caltasks. The next three classes are all accessed by way of those data types, starting with CalAlarms, which isn't a data type you can access from any CalCalendar item, specifically a CalEvent or a Caltask.

So CalAlarm's, the first method is action, and that's going to return one of a few different constants that we've defined in CalAlarm.h. That's to do with the type, whether it's a sound or an email alarm. And then depending on the type of the alarm, there will also be accessors you can use to get a path to the sound or get a string for the email address that you're sending an email reminder to. And finally, a URL, and that's a file URL that is used for both the open file and the run script.

So CalAlarm's, the final two things here, relative trigger and absolute trigger, have to do with when the alarm is set to go off. If that's defined in terms of the start time of an event or the due date of a to-do, in terms of relative to those times, then it will be defined using an NS time interval. That's the relative trigger. If it's set to go off at a statically defined time, an absolute time, that'll use absolute trigger and return as an NSDate. All right. Next up is Cal Attendee.

This is also something that's returned in an array from Cal events. So Cal attendees have a comma name that'll be the user entered string for the name of the person that's attending the event. A status is defined as a static string in the header file. That's going to be whether or not the attendee has replied and accepted or declined the invitation.

and an NSURL for the address. Now, in the kind of old style iCal events, these are events that live on a regular iCal calendar, that would always be an email address. And since it's returned with an NSURL, it's a fully qualified email address and I'll have mail to it at the beginning of it.

The reason that we're using NSURL here instead of returning it as an NSString is that in the case of a CalDAV calendar, this is a calendar that lives on a CalDAV server, you might not have an email address. Instead you'll have a URL that refers to that user on the server. So here we've got a fully qualified URL that just points to that user's record on the server.

All right, and the final class is Cal Recurrence Rule. Now, one thing I want to note here is that this class isn't really necessary if you're just displaying data. If you're just showing the event that happened in a day, iCal does the recurrence calculation for you and will tell you automatically whether or not the event belongs in that day. So this is really only if you're adding recurrence data or editing recurrence data on a currently existing event.

So Cal Recurrence Rule. Every recurrence rule has a recurrence type. And that'll be the unit of time the recurrence is defined with, whether that's daily, weekly, monthly, or yearly. It will also have a recurrence interval, which is, kind of simply put, how often the event repeats. So an interval of one means that it repeats every day or week. An interval of two means every other. Three is every third, and so on.

and a recurrence end, which is defined with a separate little class that we've tucked in the CalRecurrenceRule.h. And for an event that doesn't-- a repeating event that's never set to end, the recurrence end will just be nil. So this is a data type that's only used when you've already got the end of a repeating event defined.

And then if it's defined in terms of a number of times that the event repeats, And you'll see it defined as, it'll be returned as an unsigned integer for the number of times that it repeats. And if it's set to stop repeating after a certain date, it'll just be an NSDate.

So then depending on the recurrence type, there are some other methods you can use to access data about the recurrence. These are methods that return arrays of indices on which the event repeats for custom repeating events. So in this example, we return an NSArray that explains which days of the week an event might repeat.

and kind of in this example, where an event repeats Monday, Tuesday, Wednesday, there's going to be an array of integers. That'll be two, three, four, five, and six. Days of the month is the same idea. It's indices for the days of the month that a custom event might repeat. Same idea for weeks of the month. And finally, months of the year.

So that's all the classes in the framework. Next thing I'm going to look at is the notification model. This is kind of a high level diagram for what's going on. So when the user makes a change in iCal or iCal gets a change via sync or even over another application using the API, that change is made with the CalendarStore. And there's something in the background, the instances of the CalendarStore will talk to each other.

So the one that they're using will talk to the one that you're using, and the one that you're using sends off a notification to you. This is a local notification. You won't sign up for distributed notification, just a regular notification with NS Notification Center. This is similar to the way that it's done in AddressBook. You'll be able to use separate notifications for each of the main data types. So if you only want to know about changes that have to do with events, you can just get notifications for those types.

And within the notification itself, there's a user info dictionary. So you can either see that there's a notification and just refresh your data set, kind of using the predicate that you built before, Or you can look at the notification itself, try to the user info dictionary, and get the UID for the records that have changed. Now, we haven't really talked about UID yet. For Cal tasks, it's very simple. Each task has its own UID, and you can actually access each specific task with a method from Cal CalendarStore called TaskWithUID.

For Cal events it can get a little trickier. Non-repeating events, these are just one-off events that happen once in the user's calendar and don't repeat, they all have their own UID. Now an instance, all instances of a given repeating event, it's an event that repeats more than once, will have the same UID. So you can't differentiate between those with only UID.

Instead we've included another accessor called the occurrence. And each occurrence is unique to the instance of a repeating event. Here's a little diagram to explain that a little more clearly. All of these events, this is one repeating event, they all have the same UID. but they all have different occurrence values.

And so if you ever need to look up a specific instance, a specific Cal event, you can do that on the Cal CalendarStore by passing a UID and an occurrence. Now just to give you a kind of demo of the notification system in action, I'll show you how it works with the iCal widget.

Okay. You can see here's my iCal. And when I go into Dashboard and look at the widget, it's only got one event on for today. So I'll go back to iCal. And I'll change the movie event that I scheduled for tomorrow to be today. And when I do that, a notification gets sent off to the iCal widget, which is listening for notifications. And the iCal widget has the update. The movie appears right there.

So that's notifications. And finally, we look at how to write iCal data. So the workflow is pretty straightforward. You get the event or task that you want to use. You'll make your modifications to it. And then you just call saveEvent or saveTask in the appropriate method from the Cal CalendarStore. So looking at a code example, we have an event. In this case, we're changing its title.

and then we're calling on the Cal CalendarStore, saveEvent. There's one other parameter here we haven't talked about and that's the CalSpan. In this case we're saying CalSpan this event, only modify this event. Now the CalSpan is an enumerated type. It has several different values. This event, future events, and all events. And this is actually required to be passed in if you're making modification to an event.

And what we've done here is we've made it necessary for you, the client of the API, to force the user to make a decision as to what the change should apply to. Just like an ICAO when the user makes a change, it says, do you want to apply it just to this event or all future ones, and they make a decision there, you're going to be on the hook to do the same thing. In the case of a non-repeating event, it doesn't matter what value you pass here. They're all treated the same.

Okay, so those are the classes we talked about. That's iCal itself. And in closing, we're really excited about this. We think this is a great way to access data. We know a lot of people have been using other ways to access data, but hopefully this will make your lives easier.

And we're excited about people using this for things that aren't calendar specific, which is kind of what I feel like a lot of the things on OS X using iCal data have been. So there will be a lab tomorrow. If you have any questions, we'll be able to help you kind of integrate these calls into your application. and take all of your feedback there.