I am trying to understand how to subscribe to EventKit calendar event updates within SwiftIU.
The EventKit documentation shows how to do this in Swift (https://developer.apple.com/documentation/eventkit/updating_with_notifications).
It says to subscribe to calendar update notifications by writing:
NotificationCenter.default.addObserver(self, selector: Selector("storeChanged:"), name: .EKEventStoreChanged, object: eventStore)
It also appears that the storeChanged
function needs do be tagged with @objc
based on xcode warnings. However, when I do the below within a SwiftUI app, I get the error @objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
import SwiftUI
import EventKit
struct ContentView: View {
let eventStore = EKEventStore()
var body: some View {
Text("Hello, world!")
.padding()
.onAppear{
NotificationCenter.default.addObserver(self, selector: Selector("observeEvents"), name: .EKEventStoreChanged, object: eventStore)
}
}
@objc func observeEvents() {
print("called with updated events")
}
}
Am I doing something wrong? What would be the way to subscribe to calendar event updates within the EventStore in SwiftUI?
CodePudding user response:
You have a couple of options. One is to use an ObservableObject
that can have @objc
functions and declare it as the delegate for the notifications:
struct ContentView: View {
@StateObject private var eventDelegate = EventDelegate()
var body: some View {
Text("Hello, world!")
.padding()
}
}
class EventDelegate: ObservableObject {
let eventStore = EKEventStore()
init() {
NotificationCenter.default.addObserver(self, selector: #selector(observeEvents), name: .EKEventStoreChanged, object: eventStore)
//remember to clean up your observers later
}
@objc func observeEvents() {
print("called with updated events")
}
}
A second option would be to use NotificationCenter
's publisher
inside your View
. Note this example is incomplete, as it's unclear what actions you want to take with the notification, but it's a template to get you started:
struct ContentView: View {
@State private var eventStore = EKEventStore() //normally wouldn't use @State for a reference type like this, but it seems pointless to recreate it
@State private var pub : NotificationCenter.Publisher?
var body: some View {
Text("Hello, world!")
.padding()
.onAppear {
pub = NotificationCenter.default.publisher(for: .EKEventStoreChanged, object: eventStore)
//use sink or assign here
}
}
}