如何在 SwiftUI 中设置 addObserver?

How to set addObserver in SwiftUI?

如何在 SwiftUI 中添加 NotificationCenter.default.addObserve

当我尝试添加观察者时出现以下错误

Argument of '#selector' refers to instance method 'VPNDidChangeStatus' that is not exposed to Objective-C

但是当我在 func 前面添加 @objc 时,出现以下错误

@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes

这是我的代码

let NC = NotificationCenter.default

var body: some View {
     VStack() {

     }.onAppear {

           self.NC.addObserver(self, selector: #selector(self.VPNDidChangeStatus),
                              name: .NEVPNStatusDidChange, object: nil)

     }
} 

@objc func VPNDidChangeStatus(_ notification: Notification) {
    //    print("VPNDidChangeStatus", VPNManager.shared.status)
}

交换这个

self.NC.addObserver(self, selector: #selector(self.VPNDidChangeStatus),
                          name: .NEVPNStatusDidChange, object: nil) 

self.NC.addObserver(self, selector: #selector(VPNDidChangeStatus(_:)),
                          name: .NEVPNStatusDidChange, object: nil)

它不是 SwiftUI 原生方法,它是声明式和反应式的。相反,您应该使用 Combine 中的 NSNotificationCenter.publisher(for:object:)。

详情见Apple Documentation

这对我有用

   let NC = NotificationCenter.default



   self.NC.addObserver(forName: .NEVPNStatusDidChange, object: nil, queue: nil, 
                       using: self.VPNDidChangeStatus)


   func VPNDidChangeStatus(_ notification: Notification) {


    }

接受的答案可能有效,但实际上并不是您应该如何执行此操作。在 SwiftUI 中,您不需要以这种方式添加观察者。

你添加了一个发布者,它仍然可以监听从应用程序的非 SwiftUI 部分触发的 NSNotification 事件,而不需要合并。

举个例子,列表会在出现时更新,当它收到通知时,来自另一个视图/控制器或类似内容的已完成网络请求等。

如果出于某种原因需要触发 @objc 函数,则需要使用 UIViewControllerRepresentable

创建一个 Coordinator
struct YourSwiftUIView: View {

    let pub = NotificationCenter.default
            .publisher(for: NSNotification.Name("YourNameHere"))


    var body: some View {
        List() {
            ForEach(userData.viewModels) { viewModel in
                SomeRow(viewModel: viewModel)
            }
        }
        .onAppear(perform: loadData)
        .onReceive(pub) { (output) in
            self.loadData()
        }
    }

    func loadData() {
        // do stuff
    }
}

我有一种 NotificationCenterSwiftUI 中使用的方法。

更多信息Apple Documentation

通知扩展n

extension NSNotification {
    static let ImageClick = Notification.Name.init("ImageClick")
}

ContentView

struct ContentView: View {
    var body: some View {
        VStack {
            DetailView()
        }
        .onReceive(NotificationCenter.default.publisher(for: NSNotification.ImageClick))
        { obj in
           // Change key as per your "userInfo"
            if let userInfo = obj.userInfo, let info = userInfo["info"] {
              print(info)
           }
        }
    }
}

DetailView

struct DetailView: View {
    var body: some View {
        Image(systemName: "wifi")
            .frame(width: 30,height: 30, alignment: .center)
            .foregroundColor(.black)
            .onTapGesture {
                NotificationCenter.default.post(name: NSNotification.ImageClick, 
                                                object: nil, userInfo: ["info": "Test"])
        }
    }
}

我使用这个扩展程序,所以它在呼叫站点上更好一些:

/// Extension

extension View {
    func onReceive(_ name: Notification.Name,
                   center: NotificationCenter = .default,
                   object: AnyObject? = nil,
                   perform action: @escaping (Notification) -> Void) -> some View {
        self.onReceive(
            center.publisher(for: name, object: object), perform: action
        )
    }
}

/// Usage

struct MyView: View {
    var body: some View {
        Color.orange
            .onReceive(.myNotification) { _ in
                print(#function)
            }
    }
}

extension Notification.Name {
    static let myNotification = Notification.Name("myNotification")
}