如何在 SwiftUI 中设置 addObserver?

Posted

技术标签:

【中文标题】如何在 SwiftUI 中设置 addObserver?【英文标题】:How to set addObserver in SwiftUI? 【发布时间】:2020-03-08 03:00:42 【问题描述】:

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

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

“#selector”的参数指的是实例方法“***DidChangeStatus” 没有暴露给 Objective-C

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

@objc 只能与类成员、@objc 协议和 类的具体扩展

这是我的代码

let NC = NotificationCenter.default

var body: some View 
     VStack() 

     .onAppear 

           self.NC.addObserver(self, selector: #selector(self.***DidChangeStatus),
                              name: .NE***StatusDidChange, object: nil)

     
 

@objc func ***DidChangeStatus(_ notification: Notification) 
    //    print("***DidChangeStatus", ***Manager.shared.status)

【问题讨论】:

参观一下这可能会有所帮助 -***.com/questions/38980887/… 【参考方案1】:

交换这个

self.NC.addObserver(self, selector: #selector(self.***DidChangeStatus),
                          name: .NE***StatusDidChange, object: nil) 

self.NC.addObserver(self, selector: #selector(***DidChangeStatus(_:)),
                          name: .NE***StatusDidChange, object: nil)

【讨论】:

【参考方案2】:

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

在Apple Documentation查看更多详情

【讨论】:

【参考方案3】:

这对我有用

   let NC = NotificationCenter.default



   self.NC.addObserver(forName: .NE***StatusDidChange, object: nil, queue: nil, 
                       using: self.***DidChangeStatus)


   func ***DidChangeStatus(_ notification: Notification) 


    

【讨论】:

【参考方案4】:

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

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

这里作为一个例子,列表将在它出现时更新,当它收到通知时,来自另一个视图/控制器上的已完成网络请求或类似的东西等。

如果您出于某种原因需要触发@objc func,则需要使用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
    

【讨论】:

这行得通。然后,您可以像这样发布通知 -> self.nc.post(name: Notification.Name("RemoteContatcsReceived"), object: nil) 使用 xCode 11.5 我不必使用 @objc 耶! 如果你将它移动到一个状态对象中,那么它不会搞砸你的预览,因为状态对象在预览时没有初始化。 NotificationCenter.publisher(for:object:) 确实使用Combine。您可以从任何您想要的代码中调用一个Objective C 函数。大概您指的是定义一个目标C函数。即使这与UIViewControllerRepresentable 或协调员完全无关。你只需要在一个类中定义函数。 struct YourSwiftUIView: View @State updateYourSwiftUIView: Bool = false ... func loadData() // 做些事情 updateYourSwiftUIView.toggle() 【参考方案5】:

我有一种在SwiftUI 中使用NotificationCenter 的方法。

欲了解更多信息Apple Documentation

通知扩展n

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

内容视图

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)
           
        
    

详细视图

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

【讨论】:

很好的答案!一件事:在 Swift 中使用 Notification 而不是 NSNotification。【参考方案6】:

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

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


【讨论】:

以上是关于如何在 SwiftUI 中设置 addObserver?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 列表中设置选定的行背景颜色?

如何在 SwiftUI 中设置 ScrollView 的 contentInset

在 SwiftUI 中,如何在 XcodePreview 中设置 editMode 的环境变量

如何在 SwiftUI 的 AnyPublisher 中设置元组

如何在 SwiftUI 中设置视图中的控制器

如何在swiftUI中的List中设置空列背景颜色?