To access Reminders and Calendar data specifically, must include NSRemindersUsageDescription, NSCalendarsUsageDescription and NSContactsUsageDescription in Info.plist.
Note that we also need the contact usage because when we edit an event it can access our contact to access calendars.
Example to request access for user event.
// header
import EventKit
var eventStore:EKEventStore!
// inside viewDidLoad
eventStore = EKEventStore.init()
eventStore.requestAccess(to: .event, completion: {
(granted, error) in
if granted {
print("granted \(granted)")
// add self.fetchEvents()
}else {
print("error \(error)")
}
})
Now after we get permission from user we will fetch events.
func fetchEvents(){
let now = Date()
let calendar = Calendar.current
var dateComponents = DateComponents.init()
dateComponents.day = 60
let futureDate = calendar.date(byAdding: dateComponents, to: now) // 1
let eventsPredicate = self.eventStore.predicateForEvents(withStart: now, end: futureDate!, calendars: nil) // 2
let events = self.eventStore.events(matching: eventsPredicate)
for event in events{
print("\(event.title)")
}
}
At eventsPredicate we don’t specify which calendar, so it will return from all calendars.
EKCalendar
‘s
// declare
var calendarArray:[EKCalendar]!
// inside fetch events
func fetchEvents(){
// Date
let now = Date()
let calendar = Calendar.current
var dateComponents = DateComponents.init()
dateComponents.day = 60 // how many
let date2daysFromNow = calendar.date(byAdding: dateComponents, to: now)
// Calendars
self.calendarArray = self.eventStore.calendars(for: .event)
for calendar in self.calendarArray {
let eventsPredicate = self.eventStore.predicateForEvents(withStart: now, end: date2daysFromNow!, calendars: [calendar])
let events = self.eventStore.events(matching: eventsPredicate)
print("calendar: \(calendar.title)")
let color = UIColor.init(cgColor:calendar.cgColor) // do something with calendar color
for event in events{
print("event: \(event.title)")
}
}
}
We can use the build in iOS UI for displaying and editing calendar event: EKEventViewController and EKEventEditViewController.
We will show for both examples.
// add header
import EventKitUI
// we will need lastEvent just for get an EKEvent object
var lastEvent:EKEvent!
// add at when you looping the events
lastEvent = event
EKEventViewController
// declare this protocol
EKEventViewDelegate
// MARK: - EKEventViewDelegate
func eventViewController(_ controller: EKEventViewController, didCompleteWith action: EKEventViewAction) {
dismiss(animated: true, completion: nil)
}
Present the view controller.
@IBAction func show(_ sender: Any) {
let eventVC = EKEventViewController.init()
eventVC.event = lastEvent
eventVC.delegate = self
let navCon = UINavigationController(rootViewController: eventVC)
present(navCon, animated: true, completion: nil)
}
EKEventEditViewDelegate
// declare this protocol
EKEventEditViewDelegate, UINavigationControllerDelegate
Implementing the protocol.
@IBAction func show(_ sender: Any) {
let eventVC = EKEventEditViewController.init()
eventVC.event = lastEvent
eventVC.editViewDelegate = self
present(eventVC, animated: true, completion: nil)
}
// MARK:- EKEventEditViewDelegate
func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
controller.dismiss(animated: true, completion: nil)
}
@IBAction func create(_ sender: Any) {
let eventVC = EKEventEditViewController.init()
eventVC.event = EKEvent.init(eventStore: self.eventStore)
// !this is important to make sure event can be saved
eventVC.eventStore = self.eventStore
eventVC.editViewDelegate = self
present(eventVC, animated: true, completion: nil)
}
For creating event, we have to implement this additional function for EKEventEditViewDelegate
.
// MARK:- EKEventEditViewDelegate
func eventEditViewControllerDefaultCalendar(forNewEvents controller: EKEventEditViewController) -> EKCalendar {
let calendar = self.eventStore.defaultCalendarForNewEvents
controller.title = "Event for \(calendar.title)"
return calendar
}
We also can create an event with code.
func createEvent(){
let event:EKEvent = EKEvent(eventStore: self.eventStore)
event.title = "Test Title"
event.startDate = Date()
event.endDate = Date()
event.notes = "This is a note"
event.calendar = self.eventStore.defaultCalendarForNewEvents
try! self.eventStore.save(event, span: EKSpan.thisEvent)
}
We can create event with additional events in the future with specific rule which we using EKRecurranceRule
func createEvent(){
let event:EKEvent = EKEvent(eventStore: self.eventStore)
event.title = "Test Title"
event.startDate = Date()
event.endDate = Date()
event.notes = "This is a note"
event.calendar = self.eventStore.defaultCalendarForNewEvents
let recurrenceRule = EKRecurrenceRule.init(recurrenceWith: .daily,
interval: 1,
daysOfTheWeek:[EKRecurrenceDayOfWeek.init(EKWeekday.sunday)],
daysOfTheMonth: nil,
monthsOfTheYear: nil,
weeksOfTheYear: nil,
daysOfTheYear: nil,
setPositions: nil,
end: EKRecurrenceEnd.init(occurrenceCount: 10))
event.recurrenceRules = [recurrenceRule]
try! self.eventStore.save(event, span: EKSpan.thisEvent)
}
At first this code will make an event for the start and end date.
In addition, we will also create a recurring event in the future with this rule.
We make the reccuring every week (interval 1) for Sunday at the same time.
We may also to set daysOfTheMonth, monthsOfTheYear, weeksOfTheYear or daysOfTheYear but we only can choose either one.
This is a bit unusual to do but, at some case we might want to create our own calendar based on the app.
@IBAction func createCal(_ sender: Any) {
var localSource: EKSource?
for source in eventStore.sources{
if source.sourceType == EKSourceType.local{
localSource = source
break
}
}
var cal: EKCalendar?
cal = EKCalendar.init(for: .event, eventStore: eventStore)
cal?.title = "My App Calendar"
cal?.source = localSource!;
try! eventStore.saveCalendar(cal!, commit: true)
print("cal title:\(cal?.title), id:\(cal?.calendarIdentifier)")
}