iosswiftdelegatesekcalendar

EKCalendarChooser delegate not working from within NSObject


I have an NSObject class that consists of a basic EKCalendarChooser implementation and I am unable to get the delegate functions calendarChooserDidFinish, calendarChooserSelectionDidChange, and calendarChooserDidCancel working. I'm not sure if it is the fact that everything is in an NSObject but I wanted to keep this code separate from my other files.

I've tried a lot of troubleshooting such as not keeping the delegate methods under an extension and even making a global variable for the EKCalendarChooser as I found this post which states that non-global items could be dereferenced in contexts like this. Overall I can get the controller to pop up and it's just the way I want, but the delegate methods don't work. Below is the entire code and in my main viewController I get this to show with AddAppointments(parentViewController: self).chooseCalendarTapped()

import UIKit
import EventKitUI

class Cal: NSObject {
    
    let eventStore = EKEventStore()
    var parentViewController: UIViewController
    var CalendarChooser: EKCalendarChooser = EKCalendarChooser()
    
    init(parentViewController: UIViewController) {
           self.parentViewController = parentViewController
           super.init()
    }
   

  func chooseCalendarTapped() {
        let authStatus = EKEventStore.authorizationStatus(for: .event)
        
        switch authStatus {
        case .authorized:
            showCalendarChooser()
        case .notDetermined:
            requestAccess()
        case .denied:
            // Explain to the user that they did not give permission
            break
        case .restricted:
            break
        @unknown default:
            preconditionFailure("Who knows what the future holds 🤔")
        }
    }
    
    func requestAccess() {
        eventStore.requestAccess(to: .event) { (granted, error) in
            if granted {
                // may not be called on the main thread..
                DispatchQueue.main.async {
                    self.showCalendarChooser()
                }
            }
        }
    }
    
    func showCalendarChooser() {
        CalendarChooser = EKCalendarChooser(selectionStyle: .single, displayStyle: .allCalendars, entityType: .event, eventStore: eventStore)
        
        // customization
        CalendarChooser.showsDoneButton = true
        CalendarChooser.showsCancelButton = true
        
        // dont forget the delegate
        CalendarChooser.delegate = self
        
        let nvc = UINavigationController(rootViewController: CalendarChooser)
        parentViewController.present(nvc, animated: true, completion: nil)
    }
    
    
    
}

extension Cal : EKCalendarChooserDelegate {
    func calendarChooserDidFinish(_ calendarChooser: EKCalendarChooser) {
        print(calendarChooser.selectedCalendars)
     //   dismiss(animated: true, completion: nil)
    }
    
    func calendarChooserSelectionDidChange(_ calendarChooser: EKCalendarChooser) {
        print("Changed selection")
    }
    
    func calendarChooserDidCancel(_ calendarChooser: EKCalendarChooser) {
        print("Cancel tapped")
     //   dismiss(animated: true, completion: nil)
    }
}

Solution

  • Check if this works now:

    Declaring a var at the controller class level works here instead of having a new instance inside a function:

    Controller:

    class HomeVC: UIViewController {
        var event = EventManager()
        
        override func viewDidLoad() {
            super.viewDidLoad()
    
            event.chooseCalendarTapped(presentingVC: self)
        }
    }
    

    EventManager Class:

    import UIKit
    import EventKitUI
    
    class EventManager: NSObject {
        
        let eventStore = EKEventStore()
    
        override init() {
               super.init()
           }
        
        weak var delegate: EKCalendarChooserDelegate? = nil
        
        var presentingVC: UIViewController? = nil
        
    
        func chooseCalendarTapped(presentingVC: UIViewController) {
            
            self.presentingVC = presentingVC
            
            let authStatus = EKEventStore.authorizationStatus(for: .event)
            
            switch authStatus {
            case .authorized:
                showCalendarChooser()
            case .notDetermined:
                requestAccess()
            case .denied:
                // Explain to the user that they did not give permission
                break
            case .restricted:
                break
            @unknown default:
                preconditionFailure("Who knows what the future holds 🤔")
            }
        }
        
        func requestAccess() {
            eventStore.requestAccess(to: .event) { (granted, error) in
                if granted {
                    // may not be called on the main thread..
                    DispatchQueue.main.async {
                        self.showCalendarChooser()
                    }
                }
            }
        }
        
        func showCalendarChooser() {
            let vc = EKCalendarChooser(selectionStyle: .single, displayStyle: .allCalendars, entityType: .event, eventStore: eventStore)
            
            // customization
            vc.showsDoneButton = true
            vc.showsCancelButton = true
            
            // dont forget the delegate
            vc.delegate = self
            
            let nvc = UINavigationController(rootViewController: vc)
            
            presentingVC?.present(nvc, animated: true, completion: nil)
        }
    }
    
    extension EventManager: EKCalendarChooserDelegate {
        func calendarChooserDidFinish(_ calendarChooser: EKCalendarChooser) {
            print(calendarChooser.selectedCalendars)
            presentingVC?.dismiss(animated: true, completion: nil)
        }
        
        func calendarChooserSelectionDidChange(_ calendarChooser: EKCalendarChooser) {
            print("Changed selection")
        }
        
        func calendarChooserDidCancel(_ calendarChooser: EKCalendarChooser) {
            print("Cancel tapped")
            presentingVC?.dismiss(animated: true, completion: nil)
        }
    }