App Services • iOS, OS X • 50:04
Event Kit provides access to users' Calendar Events and now allows access to Reminders as well, on both iOS and OS X. Be sure to pencil this session in to hear from the experts on how to fetch and write Calendar Events and Reminders, and how to make the best use of the Event Kit framework.
Speakers: Scott Adler, Jeffrey Harris, Matt Lanter, Aaron Thompson
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it may have transcription errors.
Hello and welcome to Events and Reminders in EventKit. I am Jeffrey from the OS X Calendar team. And I'm very excited to be talking today about EventKit, which is in iOS, has been for a while, but is new in OS X. So if you're somebody who has never used EventKit before, we will be giving you the basics and hopefully showing you how easy it is to get started working with Events and Reminders in your applications. If you're an old hand with EventKit, we will quickly get moving on showing you what the new features are in EventKit. Okay. So let's look at exactly how that's going to be broken down. So first up we're going to talk about calendar events. This is going to be the basic intro portion. We actually introduced calendar events in EventKit a few years ago at WWDC. We'll show you a link at the end of the presentation. So if you're interested in more detail about calendar events, you should reference that, because we're just going to give you the basics. Next up, reminders, which is new in iOS and OS X.
Then EventKit Data Isolation, which is a feature currently on iOS that you're going to need to pay attention to if you're writing new apps, or even just to retrofit your old apps. Finally, we'll be talking about Calendar Store on OS X. Calendar Store is the API that you would use in versions of OS X before Mountain Lion if you wanted to work with events and reminders. All right, let's get started with calendar events.
So calendar events are here. If you're working with EventKit and calendar events, you're working with the same persistence as is used on the iPad and the iPhone and OS X for events and reminders. But in this case, we're talking about events. So one of the new features in Mountain Lion is that if you do not have calendar running and you create new events, they will still sync to Exchange and CalDAV accounts. Those of you who have been working on OS X before, that should be good news. All right. So let's actually talk in more detail about why you would care about calendar events. So you're out there making your awesome apps. Thank you very much. And you're moseying along and things are going well. And then one day you meet someone and you fall in love. And you decide, hey, let's get married. And you do. But it turns out there's all this planning involved in getting married. If you've done before. You know this is true. And you have to get together with the venue to plan out exactly how things are and scheduling with them is a hassle and get together with the cake maker and plan things out. And so you and your super geeky spouse, you get married, but then you think, that was a hassle. Let's make it easier for somebody else next time. Let's make awesome wedding. So awesome wedding, you decide is going to be this app that is going to help other people plan out all of the details. Remember the details about the florist. Remember the details about making cake and things like that. So if you put it on the app store just with those details, I think it would do well. But what's going to happen is your users are going to plan out the cake testing and they're not going to see it on their calendar because you haven't put it on to their calendar and they will plan to go golfing instead or something like that. And that's not going to work out so well with your spouse. So what you really want in this case is you want your users to see the events that are important to them that you're working with and put them on their calendar. So that -- just having events on your users' calendars is great, and that draws them in with the things that you're doing in your apps. Some other benefits are that you can put a link back to your application and draw users in that way, and you can also add alarms so that users don't forget to go and do the cake testing. Okay. So let's talk about the elements of EventKit and how you go about not missing your cake So here's the OS X calendar app, and in the left-hand corner, left-hand side, you see here are a bunch of calendars. The calendar app contains many calendars, and then each calendar contains many events.
So let's look at what these look like when we model them in EventKit. We have an EK calendar and then we have EK events. So we're talking about events right now, but let's actually stop for a second and talk about reminders and calendar events. So new in iOS 6 and iOS 10, you can work with reminders from EventKit. Now calendar events always live in EK calendars. Also reminders live in EK calendars. We call them when we talk about them to end users reminder lists, but the container for your reminders is also EK calendar.
So in this case, because our EK calendar contains EK events, we're going to show you later what exactly the field is, but we'll show it with this icon, the calendar icon. This is a calendar event EK calendar. Okay. So you have EK calendars and you have EK events. To actually access those or create them or fetch them, you need an EK event store. You just need one. It's your connection to persistence. If you make too many of them, there's not really a lot of benefit and you can't have events from one talk to another. So you just want one and make it long lived. When you create the event store, just like a calendar, the event store here, we're going to show the calendar event icon.
This event store is managing EK events. So you can create EK event stores that manage reminders or calendar events or both. In this case, we're mostly working with events. So we'll show you how in code we're going to do that. But I want to highlight that your EK calendars and your EK event stores, you want to decide whether they're for reminders or for calendar events. All right.
So let's talk more detail about EK calendar. Here we have the calendars in OS X and in iOS. And the fields that you can see in the UI map fairly closely to the fields that we provide for you on the EK calendar object. The source lets you know whether an EK calendar is in an iCloud account, whether it's an Exchange account, a local account. You have a variety of possibilities.
So that's great. Then title is fairly self-explanatory. Color is also self-explanatory, but it's worth keeping in mind that any events that you create, if you put them in a calendar, we render in our UIs, the events will be the same color as the calendar. Then finally we have allowed entity types, And this is what these icons we were talking about before. Your EK calendar either could have allowed entity types of reminders or it could have allowed entity types of calendar events.
So EK event, we talked in great detail about at that session a few years ago. So I'm not going to go into great detail, but we'll just show here the iOS event editor and the OS X inspector. Most of the fields you see here, you can edit in your EK events.
All right, so let's look at some actual code. Here is the events in a week shown in OS X calendar. Let's walk through the code that you would use if you wanted to have an application, an app, that would fetch all of the events in your calendar for a given week.
So the first thing we need to do, as we were just discussing, is create an EK event store. And in this case, we're going to initialize it with EK entity mask event because we're interested in events. Next, we want to find all of our calendars. But actually, we don't want all of our calendars. We just want the calendars that involve events. So we're going to fetch calendars for entity type EK entity type event. Then once we have event calendars, we want to create a predicate that will tell... that will describe the fetch we want to run. So the predicate needs to know what the start of the range is, the end of the range, and which calendars you're working with. So I'm not going to go into detail right now about how you create an NS state for the beginning of the week or the end of the week. We'll actually talk a little about that later, but let's imagine that you have some NS states for that, and we create a predicate. And then with that predicate, it's as easy as saying store events matching predicate, and then you have an array, and you can iterate over it, and we can print them out with their titles and start dates. And you have a not very well-sorted utility for printing out the events in your week.
All right, well, with that, now that we've talked about EK event, EK calendar, and EK event store, I'd like to invite up my colleague, Matt Lanter, to give you a more in-depth demo using calendar events. Thank you, Jeffrey. I'm Matt Lanter, and I'm an engineer on the Calendar team. Outside of work, I like playing poker with friends.
A few months ago, a group of my friends and I had an impromptu game of poker. It was a ton of fun. Some of us won money, some of us lost money, but we all had fun, which is all that matters. So much fun, in fact, we invited more and more of our friends to join. Unfortunately, it's become harder and harder to find the time that works for all of us. We tried solving this using iMessage, which works okay, but it's hard to keep track of the times everyone is suggesting.
Given that I always have my phone with me, and I'm often at my computer, this seems like a great opportunity for an app to solve this problem. Let's look at an app I created that does just this. First, I created a shared calendar called Shared Poker and invited all my friends to it. Then they can just open up this application, select that calendar, and they can suggest a time that works for them to play poker.
They can view the times everyone else has suggested. And finally, they can vote on a time that works best for them. This is great. It's made it so much easier. Now I can just open up the application and see the event tomorrow with four votes. That's the one we'll go with since it has the most number of votes.
I used EventKit to create this application. The great part about using EventKit is I was able to use the exact same model code on both iOS and OS X. Here's the iOS version. And here's the OS X version. They have different views and controllers, but it's the exact same model code underneath them. Let's look at a couple of the methods we need to implement in the model.
First, we need to fetch the calendars. We'll use this to populate the drop-down list so you can select the shared poker calendar. Second, we need to be able to view all the upcoming events so we can display that in the table view. Third, we want the ability to create events so that my friends can suggest times that work for them. And finally, the most important part of this app is voting, so that we can find the time that works best for all of us.
Let's go into Xcode and look at how we'd implement these methods. First, we'll start out and look at what the application, the app, looks like with none of these implemented. So just the view. And then we'll go through and implement them one at a time and see what it looks like after we do that. If we go to the demo machine, we see here's the application in the middle. Currently, it doesn't display anything, though. If I click calendars, nothing happens.
There's nothing in the list. And adding an event does not work either. So let's go into Xcode. And first we'll do the init method and then we'll get into some of those methods. Here we have a init. As Jeffrey mentioned earlier, we want the event store to be long lived ideally. So we'll store that as an instance variable, as a property within our model.
To do this, we'll call init with access to the types and we'll specify events, the entity mask event. We only care about events in this application, this app. We don't care about reminders. Next, we also want to keep track of the calendar the user currently has selected in the UI, which we'll use in some of our later methods.
We need a good default starting value, though. So we'll use the default calendar for new events. This is the calendar the user specified in the Settings app on iOS or within Calendar Preferences on OS X. In addition, we have some data structures we use in this model to basically store the current events we're showing to the user. We're not too concerned about those for the demo, but we'll initialize them here.
Finally, when we fetch the poker events, we want to do this on a background thread so we don't block the UI while that's happening. We'll use Grand Central Dispatch, which is a great API available on both iOS and Mac OS X, to do this. We need to create a queue as part of this. So we'll create the queue, and we'll call dispatchQueueCreate, give it a title, and then specify some options. In this case, it's a serial queue, meaning only one thing runs on it at a time.
Okay, so that's our NIT method. Let's look at how we fetch the calendars. Here we have a method calendars. Currently it just returns empty array using the new objective C array literal syntax. Let's think about what we want to do here. We want all of the events supporting calendars. We don't care about the ones that only support reminders. And then we want the ones that are writable, we can add events to. So to get the ones that support events, we will-- Call CalendarsForIndityType on the EventStore, and we'll specify entity type event. We need to filter this down, though, to the writable ones. So we'll create an array to store the filtered results.
Just in the array, and we'll call that filtered calendars. Then we'll iterate through the all event calendars. And so for each calendar and all event calendars, we want to check if we can add events to it. So we'll check, does the calendar allow content modifications? Basically, can we add items to it? If so, we'll add that to filtered calendars, and then we just want to return that filtered calendars array.
I will run this by clicking "Run" in the upper left-hand corner, and we should hopefully see that we now have the shared poker calendar, as well as my home and work personal calendars. Currently, though, I can't view the times my friends have suggested. So let's look at how we'd fetch all the upcoming events so we can populate the table view.
Here's a method, fetchPokerEvents, which we'll use to do that. As I mentioned earlier, we want to do this on a background thread so we don't block the UI. We'll use Grand Central Dispatch. and we'll call dispatchAsync, and we'll specify that queue we created earlier. Now, we want to fetch the events within a current range. For this demo, I arbitrarily chose one day in the past to two months in the future. We need to create NSDates that represent these points in time so we can then fetch within that range. To do this, we need the user's current NSCalendar.
So we'll call current calendar. And then we'll create NSDate components. So one day ago components. We'll set the day to negative 1. But we need an NSDate. To get the NSDate from the NSDate components, we'll call dateByAddingComponents to date. So we'll specify the components we just created. The NSDateDate, this returns the current date time. And that will return the NSDate one day ago. We want to do the same thing for two months in the future. So here we do that. The main difference is our month is a positive 2. Now that we have those two NSDates, we want to get a predicate from the event store that encapsulates those two dates and a calendar we'll search in.
We'll call the predicate for events with start date, specify one day ago. The end date is two months in the future. And the calendars we will use the new Objective-C array literal syntax. So this takes in an NSArray. So we're basically specifying an NSArray with the selected calendar we created in a Nib. Now that we have this predicate, we want to run it to get the matching events.
We will, on the event store, call events matching predicate, pass in that predicate, and that will give us an array of results. We need to filter this down, though, by title. We only want the events whose title is Poker. We'll create a standard in this predicate to do this.
So we'll call a predicate format where the title -- so I counter that title -- matches our parameter, which in this case is poker. Then we'll just run that predicate by calling filtered array using predicate, passing that predicate, and we'll set that back to our results array. Now that we have this array of results, we want to update those data structures we created in there. We're not concerned about everything we do as part of that for this demo, so we have of a helper function that will do that, update those internal data structures.
Now that we have gotten all the results, we want to notify the UI so that it can update and refresh and show the user the latest events. We want to do this on the main thread, since it's likely the UI will do some work when it gets a notification.
we will dispatch async back onto the main queue, which runs on the main thread, and we'll post a notification saying our model changed. I'll run this again. And now we should hopefully see all the upcoming events. So we see here shared poker and then we see all the upcoming events. So we see today at 6:00 p.m., tomorrow 7:00 p.m. and then Friday at 8:00 p.m. Currently tomorrow is winning. However, I would really like to play tonight at 10:00 p.m. So I'd like to create a new time. Unfortunately, because we can't add new events. So let's look at how we would add events.
Here we have add event with start time, which takes in the start time. And first we want to create a blank EK event. Then we'll set a bunch of properties on this event, and finally we want to save this event. to create the blank EK event. We'll call EK event, event with event store, and this will basically create a new event that's bound to the specified event store.
Now we want to set several properties on it. So here we set the title, time zone, start date, end date. And for the demo, we just always assume the duration is one hour. And then we specify what calendar this event should go into. We want to save this event now.
So we'll call saveEvent, pass in that event. We specify a span. The span only matters for non-recurring events. Or sorry, it only matters for recurring events. And this is not a recurring event. So it doesn't really matter what we put here. But if you'd like to learn more about recurring events, I'd suggest watching the WWDC talk from two years ago. We specify that we commit yes, so we'll immediately commit this. And then if there is an error for some reason, we'll log that out. An example of an error would be if I did not specify the start date, I would get an error.
Let's run this, and we should hopefully see. We see all the times people have suggested. I'll create one for 10 p.m. tonight. tonight. And now we see 10:00 PM. Awesome. I'd like to vote on this, though, so I can convince my friends to come to this time tonight. We have increased vote on event, which takes an event.
First, we want to get the current phone count. So we'll call event number of votes. You may be thinking, "I've never realized there's a number of votes field on an event." This field is created using custom code, specifically using a category, which I did for this demo. We stored it in the notes field for this demo for simplicity's sake. In an actual application, you might want to store it on an external server and then tie it back to this event with some sort of event identifier.
But now that we have this number of votes, we want to increase it by one. So we'll just set the number of votes plus one. And since we modified the notes field, we want to save this event. We'll call save event. And this is the same thing we just did when we created a new event. We'll run this again. And hopefully, I should be able to vote on it. So here's the one I just created. I'll click. And now we have one vote, which is awesome. We will-- the great part about this, as I mentioned earlier, is I can use the exact same model code for both iOS and OS X.
So let's try and-- let's build the iOS version. And I already created the Viewer and Controller for it. I just need to run it, and then hopefully it will use this model we have just created. So I'll switch to the mobile target. Build this. And then we'll switch to my device. And here we see the application running. We see the 10PM one I just created. I'll click on that and increase the vote to 2. We see in this application, we see all the times my friends have suggested. I can click calendars in the upper left-hand corner if I want to change the calendar. I can create a new event using plus in the upper right-hand corner.
And so that's the iOS application. And this uses the exact same model code we just created. If we go back to the demo machine, we see that it is automatically updated, so the 10:00 PM one has two votes now. This is great. EventKit takes care of all the syncing for you behind the scenes.
You notice all we do is we save the event, and then everything is taken care of for you. Okay. I'm showing you... how easy it is to create an application using EventKit. The great part about EventKit is you can have the exact same model code to create both an iOS and an OS X version of the app. Now, over to Aaron, who will talk to you more about reminders.
I'm Aaron, I'm an iOS EventKit engineer, and I'm excited to talk to you about reminders in EventKit today. In iOS 5, we introduced this great new Reminders app that helps you keep track of all the things you have to do on both your iPhone and iPad. And then in the OS X Mountain Lion, we brought it to the Mac. So your Reminders are really useful because they're on all your Apple devices. But there's one place they haven't yet been, and that's your apps. So now I'm excited to show you how you can integrate reminders into your own apps. And I'm looking forward to seeing the interesting and awesome ways you use them in your apps.
So, you may already be familiar with something that uses EventKit reminders. That's Siri. Siri has been using EventKit behind the scenes to create reminders when you ask it to. So, to go through this, let's take an example of a task I've been putting off for a while. My cat has started smelling a little bad lately, and I need to give her a bath. And some of you know all too well why I might have been putting off this task. So I'm going to ask Siri to create a reminder to help me. I want to ask Siri, "Remind me to give my cat a bath." Up will pop something like this.
A reminder. So how would we create this using EventKit code? Well, we're going to start out just like we were doing to create an EK event. That is, we need an EK event store. And because we want this to be an event store for reminders, we'll in it with access to entity types and pass in EK entity mask reminder.
Next, we need an EK reminder object to represent this reminder. So we'll just create this using reminder with event store. Next, we're going to set a couple of properties on it. First, the title, give my cat a bath. And then the calendar. Now when you create an event or a reminder through Siri, it will use the default list for new reminders that you specified in your settings. So we're going to do the same here by using default calendar for new reminders. Next, all we have to do is save that reminder using EK Events Store's SaveReminder method.
Now, I might keep putting off this event or this task if it never pops up and reminds me. So let's talk about how to create a time-based reminder. If I were asking Siri, I'd ask, "Siri, remind me to give my cat a bath tomorrow at 4:00 p.m." Let's look at the code.
To represent when I want the alarm to fire, I'll use an EK alarm, alarm with absolute date specifically. If you're already familiar with creating alarms on events, it works very much the same way. Now, you'll notice here that we kind of left out how to get this tomorrow at 4:00 p.m. date, but this bears more investigation.
Let's talk about date math. Now, This is -- how many of you know what this number means? 86,400. That's the number of seconds in a day, right? Except when it's not. Thanks to our good old friend daylight savings time, this will be wrong probably twice per year, but only probably in inconsistent locales and at inconsistent times on inconsistent days. So how on earth are we going to get this right all the time? We're going to use NSCalendar, like Matt mentioned earlier. Specifically, we want to use the Gregorian calendar because EventKit for Reminders at this time only supports the Gregorian calendar. So now that we've specified this NSCalendar, we need to go from today to tomorrow. So we'll use NSDateComponents and set its day component to 1.
Next, we want to add one day to the current date. If you're not familiar with the NSDate API, NSDate is simply a wrapper around an absolute time, and the date method returns an absolute time for the current time right now. So I'll use that calendar to get a new NSDate for tomorrow by adding these one-day components to the current date.
Now that I have the NSDate for tomorrow, what I need to do is get the components out of that so that I can set them to a specific time. So I don't care about the hours, minutes and seconds yet. I just want to get the year and the month and the day for tomorrow. We're going to put in ERA just for future forward compatibility.
Then, so you see we have the components from that date, and that'll give us, and as a date components for tomorrow at 4:00 p.m., sends the time. Then we want to specifically set the hour to 16, this is 24 hour time we're dealing with, and then we'll set the minute and second to zero.
And finally, one last thing, because the EK_ALARM API wants an NSDate, not NSDate components, we're going to get an NSDate back from those components using NSCalendar's dateFromComponents method. All right, so we're done talking about how to get this crazy date, but it'll be right in all locales and all time zones.
Again, we're going to create this EK alarm with an absolute date, and then we're going to add that alarm to the reminder. Before we save, though, there's one last step. We have to set the due date components as well. This helps it show up as overdue after the reminder has fired in the reminders app. So we're going to set the due date components property to those NSDate components that NS calendar helped us calculate just a second ago. Finally, we'll save that reminder. Now, let's talk about location-based reminders.
We all know that giving a cat a bath can be very hazardous to your health. So, I'm going to want a little bit of armor. Specifically, I want to ask Siri, "Remind me to pick up a chainmail suit when I leave work, so those claws of fury don't leave a flesh wound." So, how do we create a reminder that looks like that?
We're going to use an EK structure location object. This is new in the new Remiters API. And this will create using location with title. And the title here is something that you use to show your users what this location is. Next, we need to show where on Earth work is. So we're going to use the CLLocation class for that. Now, normally, you might want to use CLGeocoder other core location APIs to get this for you, but I just happen to know the location for work off the top of my head. So I'm going to create this CL location object using a latitude and longitude specifically. Then I need to set that on the structure location as the geolocation property.
Next, this is still an alarm after all. It's still popping up at you. So I'm going to create an EK alarm, just using alloc init without any date or time. And next, I'm going to set a couple properties on it. First, the structure location to what we just created. And then, because I want this to be when I leave work, as opposed to when I arrive at work, I'm going to set the proximity property to EK_ALARM_PROXIMITY_LEAVE. Finally, as before, I'm going to add this alarm to the reminder and save the reminder.
All right. Now, what if my poor cat gets dirty on a regular basis? How do I have it remind me to give my cat a bath every month, for example? If I were asking Siri this, she'd pop up something like that. In code, it's easy. We'll use an EK recurrence rule to represent how it repeats. If you're already familiar with EventKit for events, this should be old hat to you. So we'll create this recurrence rule with a recurrence frequency of monthly and an interval of one to specify that it's every month. Then we're going to add this recurrence rule to the reminder. And before we save, there's one more step. We have to set the start date components for when it starts repeating. Now we already talked in depth about how to get the NSDate components for any time. So I'll just use the NSDate components for right now. Finally, we're going to save this reminder.
Now, there is a slight difference in how events and reminders that repeat regenerate. If you look in your calendar, you'll see repeating events generating out indefinitely. However, if you look in the reminders app, you don't see a million reminders of the same thing. You only see the next one that's not due, that hasn't been completed. So once you check that one completes in the reminders app, that's when it will generate the next instance. Speaking of chucking reminders complete, let's talk about how to do that.
In the Reminders app, if I were to check a complete, it would go from looking like that to that. And that's what we call the completed card. So how do we do that in code? Simple. All we have to do is set the completed property and then save the reminder.
Now, the completion date, which you'll see right there, is when you completed an event or a reminder. It's automatically set to the current time when you set this completed property to yes and save the reminder. But what if you were importing some old data and some of the reminders in that old data were already completed at a specific time that you know? Well, to set that arbitrary time in the past, we would use the completion date property of ekReminder.
All right, so that's all there is to it. We've gone over how to create all sorts of reminders, including time-based reminders that fire at a specific time in the future. We talked about how to use location-based reminders using EK structure location. And we talked about how to make reminders that repeat using EK recurrence rule. And finally, we all know how to mark a reminder done. So that's great, but what if I have an existing app that uses reminders? I'd like to invite up Scott to talk about that.
We want to talk a little bit about how to integrate reminders into an application. And one of the things that I hope you're taking away from this whole session is that we're hopefully not talking to a room full of 500 people writing calendar and to-do list applications, that you guys have other applications you're writing and you want to integrate reminders and also events into your apps. So this -- we thought let's look for something that might be a good example. So I found this example from a couple years ago that was a recipes application. And so I spent a little bit of time cleaning it up, making it look a little nicer. And then I thought recipes, you know, you tap on a recipe here and you get a list of ingredients. And that sounds like a great place to add reminders where I can make my shopping list right away in this app. So I can just integrate it using EventKit. So I'm going to go over and show you. And I now have the recipes project here. And let me go to the view controller for the detail view. So that's the view I had just shown you. And basically, I added a new table row to the recipes app. And it calls make shopping list whenever you tap on it. So it's very similar to what you saw with creating events. You just create an event store. And like everyone said, you use the mask reminder here. And I added an event store to this view controller so I can hold onto it. So in case they want to create lists, multiple lists, that this will be around for a while. And then I call a function here called create reminders. And that's where the heavy lifting goes on. So create reminders.
So first thing we want to do is we want to create an EK calendar. So this will be a reminder list. So I create an EK calendar. And I say it's going to be of type reminder. And then I'll use the event store that we created before. Then I'll make the title of it the recipe title. So if it's chocolate cake, I'm going to make a chocolate cake list. And then I'm going to use the source, which is the account that we're going to store this list in, I'm going to get it from the default calendar for new reminders. So if your default calendar happens to be on your iCloud account, this new calendar will show up in your iCloud account. If your default calendar is local, it'll show up locally to your device. There's lots of options you could do here. You could actually ask people based on what sources they might have and things like that. But we wanted to keep this simple for demo purposes. And then I'm going to save this calendar. And again, always check the saved return value and make sure that we don't have errors. Then we're going to go through and create all these reminders. So we already have an array of ingredients. We'll just loop through that array. We'll create a reminder for each ingredient using the event store. And then we'll set the calendar to the calendar we just created.
Next, we're going to set the title to the name of the ingredient, and the notes we'll set to the amount. And then finally, we're going to save each reminder. Now, the important thing here, and we haven't really talked about this too much, is that in this save reminder call, we're going to set commit right here to no. And the reason we're doing that is if you were to set commit to yes, we'd have a database save every single reminder that you're creating. So if you had 50 ingredients, there'd be 50 database saves. That'd be kind of slow. So we're just going to say commit no. And then at the very end here, we're going to commit the whole event store. So what that'll do is that'll then actually do a database save of all those reminders that you didn't commit before. So it's just a little optimization. And then I just added a little UI alert view in this case that will put up an alert saying, hey, your reminder was created. So let me show you an example of what that looks like here. And so here's my recipes app.
And these are all my recipes. And if I pick chocolate cake, I can scroll down and here's my new create shopping reminders. And it's right after my whole list of ingredients. So I'm gonna tap this. and it gets my alert up that says, shopping reminders have been added. So if I say okay here, If I go to the Reminders app, here's my regular reminders list, and there's now Chocolate Cake, which was just created. And there's my chocolate cake. So that's the basic demo.
So next I wanted to talk about something that's new in iOS 6, which is EventKit data isolation. So exactly what is it? Well, this is what's under privacy and settings in iOS 6. We've talked a lot about this in other sessions. But the point here is that your apps now have to ask for permission to get to reminders and events. So when you want access to it, we're going to ask the users, just like you're used to with location in the past.
So they're prompted whenever your EK event store is instantiated. Now, this is really important to remember because we want you to keep your EK event store around a lot, but we don't want you to create it right at the beginning of your app unless it's needed right at the beginning of your app. So the reason for this is that, like in the recipes application, we don't want to ask to access reminders when they're just looking at their recipes. We only want to ask them when they actually tap on the make shopping list. And that's because they don't want necessarily to say, yeah, I want to look at my recipe. Why do you need reminders? They want it to be at the time they're doing something that actually needs access to reminders. Now, if you're writing something that's reading reminders right away and doing stuff, then create your EK Event Store right away, and you'll ask the user. Now, this will only ask the first time they ask for it, and then they'll decide yes or no. And then the next time your app runs, and you won't ask again.
Now the important thing is when we do ask that your code is not blocked. So this is an asynchronous call that brings up this alert view. Now it's important because you may have written apps in the past that just go ahead and do stuff if you're doing events. If you're doing reminders, it's all new, so you should do this correctly. But if your app exists right now and you just go and do things, you may get errors, like if you try to save things before the user has said, yes, you have access, you might actually get errors back saying you don't have access to do this. So we'll show you some tricks on how to deal with this. Then what happens is while your app is -- while the asynchronous dialogue is up, your app will eventually get an event store change notification and then you'll be able to check and see what did they say. Did they say yes, you're allowed or no, you're not allowed.
And then what's really important is this usage description. Now that's what's highlighted in yellow here. And that's what you're going to be automatically shown to the user saying why you need access to events or reminders. And it's really important to be specific here and cover any of the cases that your app might use. You're only going to be asked once for your whole app. So if you have multiple places you're using reminders or multiple places using events, make sure it covers those cases. But try to give something clear that people, you know, everyday people, not just developers will understand.
So let me show you how we do this. And if we go back to, I have some code way up here. So I'll comment out this make shopping list. And I'll show you the code we wrote to actually make the shopping list, this time dealing with data isolation.
You might recognize the beginning of this. We create the event store. Same thing as what we did before, and again, we're creating it when they hit the button. That's the important thing is that we'll be asked when we hit the button. And... And then we actually are going to register for the event store change notification, which will call this function event store changed.
Then we're going to check our authorization status. Now, the main thing here with checking authorization status is that we want to see if they've already been authorized, they've already been denied or restricted, and also if they're pending. And pending is that asynchronous call I talked about. So if we're authorized, we're just going to go ahead and create the reminders just like we did before. If they're denied or restricted, we're going to put up an alert that we have created -- that you will create or however you want to deal with them being denied or restricted. And in this case, we put up an alert that says you're not allowed to use this and to use reminders and you can go change it in your settings if you want to. If they're restricted, that could be someone turned on restrictions that doesn't allow us to even ask them because you're not allowed to change your access to reminders. And then if they're not determined, that's the asynchronous call. So in this case, I added a flag to this view controller saying we're pending authorization and I'm going to set that flag, and then I'm not going to do anything until we get our notification back. So let me show you that notification. Here we go. And we'll pass through, we don't change the code at all for create reminders, same code as before.
And here's our event store changed function. And what we're gonna do is if we were setting this pending authorization flag, then we're gonna go in and we're gonna look and see what our current authorization status is. Most likely they've changed the authorization status. So if it's now determined, we're gonna go and we're gonna say, okay, are we authorized?
If we're authorized, we create reminders. If we're not authorized, we're gonna present an alert that says, hey, you're denied, you're not allowed access to reminders. Now, there's one other thing I didn't show, which is here inside the info P list, let's see if we can, it's kind of small here, but if you can see down here, there's this reminders usage description. And there's also other ones for contacts usage description and calendars and location. So what you do is you set in here that user presented string that says why you need access to your reminders. and you can, we just said create new shopping lists for recipe ingredients here. So that's where you're gonna set it for your whole application.
So you might have different, you might use locations, you might have one for location in there. And then we can just build and run this. So let me go to my phone here. So I actually am running the version that knows about restrictions, or knows about privacy. So let me go to settings and show you how this shows up in settings. So we go inside of privacy, And we can go to Reminders, and you'll see that Recipes has already been given access. So what I'm gonna do is I'm gonna turn off Recipes and no longer allow access, and you'll see how this works. So I'm gonna go back to Recipes.
I'm going to try a different recipe this time. And I'll say create shopping reminders. And it's saying the shopping list was not added. Now, this is the alert that I created, not a system alert. And this is because I got something back right away that checked my authorization status and said we're not allowed to add it, so I didn't even try. So that's fine. That's good.
So let me leave here and I'll quit reminders. I'll quit recipes. And let me show you one other thing that's really useful if you're developing here, which is I'm going to go back into settings. If you go to your general settings, all the way down there's a reset section, and the very bottom of reset is reset location and privacy. So what this does is it gets rid of all of your privacy settings. So any apps that have been granted or denied access to location or privacy will be reset. Now, users aren't going to do this very often, but when you're developing and you want to test all these different code paths, you'll want to do this to see what what it's like to start over. So I'm going to reset and reset these settings.
And now, if I launch the recipes app again, and let's try the crepes. I scroll down here, I'll say create shopping list. And now this is a system alert that comes up with our usage string right here in here. So it says create new shopping list for recipe ingredients and I can allow or not allow. So if I say allow, what's happening behind the scenes is we're talking to the system service that is gonna allow us to create reminders. And then we get our message back. So we can see that it actually worked. And if I go to the reminders app, we'll see that I actually have now grapes right there. That's it. And that's everything.
So one thing to remember about doing -- adapting your code for privacy is that even if you've used EventKit before in your app, you may want to go look at the privacy information and what's in there now so that you can correctly present a usage description. If you have an existing app, it's going to present this thing the first time they launch it in iOS 6. So you'd like them to have a good experience with it. So you can update your app to actually put in these usage descriptions and actually check the authorization status.
So now I'd like to bring Jeffrey back up to talk about Calendar Store. All right. So Calendar Store, if you've never used it before, you probably never will because Calendar Store is deprecated. If you have used it before and you're using it in your app, before you get out the pitchforks, I want to make a pitch that it's not as bad as it might seem. EventKit is actually based on Calendar Store and it's very similar. So the main model elements are in calendar store, CalCalendar, CalEvent, Caltask, CalCalendarStore. In EventKit, it's pretty much changing the prefix.
We switched our nomenclature from task to reminder, but, you know, not that big a deal. Let's actually look at the code we were looking at before where we were fetching a list of events from the week. And so this is the EventKit version, and I've highlighted in yellow here the places that you would need to change between calendar store and EventKit. I'm not expecting you to read through them really quickly. We went through this code before, but so here's the calendar store version. It's very similar. Mostly we're changing prefixes from ek-event to cal-event. Occasionally we're changing the method names very slightly. So we're not talking about hundreds of hours of work to switch to EventKit. And in addition -- oh, so there's the calendar store. We'll go back to EventKit. In addition, we have some carrots, not just the stick of deprecation. There are benefits of going to EventKit. The big obvious benefit is that if you have OS X application that you write using Event Kit, you can much more easily port it to iOS. Also, there are some fields that developers have requested that are available in Event Kit that were not available in Calendar Store. For instance, the time zone is now available. You can access the time zone on events. You can also find out whether a calendar will allow you to create events or create reminders. So not that big a deal to transition from Calendar Store to EventKit. All right. So that is about it. Here's the link that we were discussing before to more details about Calendar Events and EventKit from a few years ago. If you're interested in many of the things that we talked about, there's privacy support. They'll go into a lot more detail about this. At that session, if you're interested in working with CL location, there's a great session on that. And internationalization will be a good one if you are confused would like to make sure that you're bulletproofed in your NSDate creation. So there are lots we talked about. There are new features in Event Kit. It's available on OS X and reminders. Also it's easy. So please go use it in your apps. Thank you very much. Have a great day.