How to add an event in the device calendar using swift?

SwiftEkeventEkeventstore

Swift Problem Overview


I would be interested in knowing how to add a calendar event in the device, but using swift. I know there are some examples made in Objective-C, but at the moment nothing in swift. Many thanks.

Swift Solutions


Solution 1 - Swift

Note: If your app is crashing with This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSCalendarsUsageDescription key with a string value explaining to the user how the app uses this data., you'll need to add NSCalendarsUsageDescription to your info.plist. Can follow the example here.

Swift 5.0 Version

import Foundation
import EventKit

let eventStore : EKEventStore = EKEventStore()
      
// 'EKEntityTypeReminder' or 'EKEntityTypeEvent'

eventStore.requestAccess(to: .event) { (granted, error) in
  
  if (granted) && (error == nil) {
      print("granted \(granted)")
      print("error \(error)")
      
      let event:EKEvent = EKEvent(eventStore: eventStore)
      
      event.title = "Test Title"
      event.startDate = Date()
      event.endDate = Date()
      event.notes = "This is a note"
      event.calendar = eventStore.defaultCalendarForNewEvents
      do {
          try eventStore.save(event, span: .thisEvent)
      } catch let error as NSError {
          print("failed to save event with error : \(error)")
      }
      print("Saved Event")
  }
  else{
  
      print("failed to save event with error : \(error) or access not granted")
  }
}   

Reference : https://gist.github.com/mchirico/d072c4e38bda61040f91

Solution 2 - Swift

Swift 3.0 compatible:

func addEventToCalendar(title: String, description: String?, startDate: Date, endDate: Date, completion: ((_ success: Bool, _ error: NSError?) -> Void)? = nil) {
    let eventStore = EKEventStore()
    
    eventStore.requestAccess(to: .event, completion: { (granted, error) in
        if (granted) && (error == nil) {
            let event = EKEvent(eventStore: eventStore)
            event.title = title
            event.startDate = startDate
            event.endDate = endDate
            event.notes = description
            event.calendar = eventStore.defaultCalendarForNewEvents
            do {
                try eventStore.save(event, span: .thisEvent)
            } catch let e as NSError {
                completion?(false, e)
                return
            }
            completion?(true, nil)
        } else {
            completion?(false, error as NSError?)
        }
    })
}

And also import EventKit

So you can easily call this method from everywhere:

addEventToCalendar(title: "Girlfriend birthday", description: "Remember or die!", startDate: NSDate(), endDate: NSDate())

If you prefer, you can put this method inside an utiliy class and define it as 'static'.

Solution 3 - Swift

You need to add "Privacy - Calendars Usage Description" to info.plist. Following code works with latest version of xcode and swift 3.

import EventKit
class EventHelper
{
    let appleEventStore = EKEventStore()
    var calendars: [EKCalendar]?
    func generateEvent() {
        let status = EKEventStore.authorizationStatus(for: EKEntityType.event)
        
        switch (status)
        {
        case EKAuthorizationStatus.notDetermined:
            // This happens on first-run
            requestAccessToCalendar()
        case EKAuthorizationStatus.authorized:
            // User has access
            print("User has access to calendar")
            self.addAppleEvents()
        case EKAuthorizationStatus.restricted, EKAuthorizationStatus.denied:
            // We need to help them give us permission
            noPermission()
        }
    }
    func noPermission()
    {
        print("User has to change settings...goto settings to view access")
    }
    func requestAccessToCalendar() {
        appleEventStore.requestAccess(to: .event, completion: { (granted, error) in
            if (granted) && (error == nil) {
                DispatchQueue.main.async {
                    print("User has access to calendar")
                    self.addAppleEvents()
                }
            } else {
                DispatchQueue.main.async{
                    self.noPermission()
                }
            }
        })
    }
    func addAppleEvents()
    {
        let event:EKEvent = EKEvent(eventStore: appleEventStore)
        event.title = "Test Event"
        event.startDate = NSDate() as Date
        event.endDate = NSDate() as Date
        event.notes = "This is a note"
        event.calendar = appleEventStore.defaultCalendarForNewEvents
        
        do {
            try appleEventStore.save(event, span: .thisEvent)
            print("events added with dates:")
        } catch let e as NSError {
            print(e.description)
            return
        }   
        print("Saved Event")
    }
}

Solution 4 - Swift

I was able to adjust this and eliminate the compiler error mentioned in the comments to the answers above (and a few others), as follows:

 var eventStore : EKEventStore = EKEventStore()
    
    // 'EKEntityTypeReminder' or 'EKEntityTypeEvent'
    
    eventStore.requestAccessToEntityType(EKEntityType.Event, completion: {
        (granted, error) in
        
        if (granted) && (error == nil) {
            print("granted \(granted)")
            print("error \(error)")
            
            var event:EKEvent = EKEvent(eventStore: eventStore)
            
            event.title = "Test Title"
            event.startDate = NSDate()
            event.endDate = NSDate()
            event.notes = "This is a note"
            event.calendar = eventStore.defaultCalendarForNewEvents
            
            eventStore.saveEvent(event, span: EKSpan.ThisEvent, error: nil)
            
            print("Saved Event")
        } 
    })

However, I still get the following error at the bottom regarding "EKSpan.ThisEvent" : Incorrect argument label in call (have ':span:error:', expected ':span:commit:').

I tried changing "error" to "commit," but it gave me a compiler error saying it expected a Bool instead of nil. It seems like a problem having to do with updates in swift syntax.

Edit: I ended up following this tutorial and was able to get it to work.

  1. First, ask permission to access the calendar and (if that permission is granted) call a function to add the event.

     var savedEventId : String = ""
    
     func requestAccessPermission() {
         let eventStore = EKEventStore()
     
         let startDate = NSDate()
         let endDate = startDate.dateByAddingTimeInterval(60 * 60) // Ends one hour later
     
         if (EKEventStore.authorizationStatusForEntityType(.Event) != EKAuthorizationStatus.Authorized) {
             eventStore.requestAccessToEntityType(.Event, completion: {
             granted, error in
                 self.createEvent(eventStore, title: "Test Title", startDate: startDate, endDate: endDate)
             })
         } else {
             createEvent(eventStore, title: "Test Title", startDate: startDate, endDate: endDate)
         }
     }
    
  2. The function that is called in the above code snippet to add the event:

     func createEvent(eventStore: EKEventStore, title: String, startDate: NSDate, endDate: NSDate) {
         let event = EKEvent(eventStore: eventStore)
         event.title = title
         event.startDate = startDate
         event.endDate = endDate
         event.calendar = eventStore.defaultCalendarForNewEvents
         do {
             try eventStore.saveEvent(event, span: .ThisEvent)
             savedEventId = event.eventIdentifier
         } catch {
             print("Error Saving")
         }
     }
    

Solution 5 - Swift

This was really slow on iOS 11.2 Xcode 9.2, so I modified Luca Davanzo's answer to use queues (works a lot faster):

func addEventToCalendar(title: String, description: String?, startDate: Date, endDate: Date, completion: ((_ success: Bool, _ error: NSError?) -> Void)? = nil) {
        DispatchQueue.global(qos: .background).async { () -> Void in
            let eventStore = EKEventStore()
            
            eventStore.requestAccess(to: .event, completion: { (granted, error) in
                if (granted) && (error == nil) {
                    let event = EKEvent(eventStore: eventStore)
                    event.title = title
                    event.startDate = startDate
                    event.endDate = endDate
                    event.notes = description
                    event.calendar = eventStore.defaultCalendarForNewEvents
                    do {
                        try eventStore.save(event, span: .thisEvent)
                    } catch let e as NSError {
                        completion?(false, e)
                        return
                    }
                    completion?(true, nil)
                } else {
                    completion?(false, error as NSError?)
                }
            })
        }
    }

Solution 6 - Swift

same with location and alert

   func addEventToCalendar(title: String, description: String?, startDate: Date, endDate: Date, location: String?, completion: ((_ success: Bool, _ error: NSError?) -> Void)? = nil) {
    DispatchQueue.global(qos: .background).async { () -> Void in
        let eventStore = EKEventStore()
        
        eventStore.requestAccess(to: .event, completion: { (granted, error) in
            if (granted) && (error == nil) {
                let alarm = EKAlarm(relativeOffset: -3600.0)
                let event = EKEvent(eventStore: eventStore)
                event.title = title
                event.startDate = startDate
                event.endDate = endDate
                event.notes = description
                event.alarms = [alarm]
                event.location = location
                event.calendar = eventStore.defaultCalendarForNewEvents
                do {
                    try eventStore.save(event, span: .thisEvent)
                } catch let e as NSError {
                    completion?(false, e)
                    print ("\(#file) - \(#function) error: \(e.localizedDescription)")
                    return
                }
                completion?(true, nil)
            } else {
                completion?(false, error as NSError?)
                print ("\(#file) - \(#function) error: \(error)")
            }
        })
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJavier Calatrava LlaveríaView Question on Stackoverflow
Solution 1 - SwifttoofaniView Answer on Stackoverflow
Solution 2 - SwiftLuca DavanzoView Answer on Stackoverflow
Solution 3 - SwiftRujoota ShahView Answer on Stackoverflow
Solution 4 - Swiftkamisama42View Answer on Stackoverflow
Solution 5 - SwiftIgnacio ValdiviesoView Answer on Stackoverflow
Solution 6 - SwiftDmihView Answer on Stackoverflow