Matt
Matt

Reputation: 1187

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)
    }
}

Upvotes: 0

Views: 120

Answers (1)

RTXGamer
RTXGamer

Reputation: 3750

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)
    }
}

Upvotes: 1

Related Questions