如何在 SwiftUI 中订阅 EventKit 的变化?

How to subscribe to EventKit changes in SwiftUI?

我正在尝试了解如何在 SwiftIU 内订阅 EventKit 日历事件更新。

EventKit 文档在 Swift (https://developer.apple.com/documentation/eventkit/updating_with_notifications) 中展示了如何执行此操作。

上面写着订阅日历更新通知:

NotificationCenter.default.addObserver(self, selector: Selector("storeChanged:"), name: .EKEventStoreChanged, object: eventStore)

根据 xcode 警告,storeChanged 函数似乎也需要用 @objc 标记。但是,当我在 SwiftUI 应用程序中执行以下操作时,出现错误 @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")
    }
}

我是不是做错了什么?在 SwiftUI 的 EventStore 中订阅日历事件更新的方式是什么?

你有几个选择。一种是使用可以具有 @objc 函数的 ObservableObject 并将其声明为通知的委托:

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

第二种选择是在 View 中使用 NotificationCenterpublisher。请注意,此示例不完整,因为不清楚您希望对通知采取什么操作,但它是帮助您入门的模板:

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