如何在 SwiftUI 中接收通知中心帖子

Dav*_*vid 3 publish-subscribe swiftui combine

我看过十几个关于如何使用合并并接收Notification正在完成的任务的教程。看起来它们都显示线性代码 - 发布者和接收者都在同一个地方,一排又一排。

发布通知就像下面的代码一样简单:

// background download task complete - notify the appropriate views
DispatchQueue.main.async {
    NotificationCenter.default.post(name: .dataDownloadComplete, object: self, userInfo: self.dataCounts)
}

extension Notification.Name {
    static let dataDownloadComplete = Notification.Name("dataDownloadComplete")
}
Run Code Online (Sandbox Code Playgroud)

SwiftUI 有onReceive()修饰符,但我找不到任何方法将上面的内容连接到已发布通知的“侦听器”。

a如何View收到这个Notification

Dav*_*vid 5

仅供参考,经过几天的阅读和整理令我困惑的组合教程,我发现了这两种接收通知的方法。为了方便起见,它们包含在同一个视图中。(省略了一些不相关的细节。)

就我而言,提取(在后台线程上执行)是将多个实体的信息批量加载到核心数据中。获取完成后视图未更新。

// in the background fetch download class
    ...
    var dataCounts: [DataSources.Source : Int] = [:]
    ...

    // as each source of data has been imported
    self.dataCounts[source] = numberArray.count
    ...


// in a view
import Combine

struct FilteredPurchasesView: View {
 
    private var downloadCompletePublisher: AnyPublisher<Notification, Never> {
        NotificationCenter.default
            .publisher(for: .dataDownloadComplete)
            .eraseToAnyPublisher()
    }
    
    private var publisher = NotificationCenter.default
        .publisher(for: .dataDownloadComplete)
        .map { notification in
            return notification.userInfo as! [DataSources.Source : Int]
        }
       .receive(on: RunLoop.main)

    var body: some View {
        List {
            ForEach(numbers.indices, id: \.self) { i in
                NavigationLink(destination: NumberDetailView(number: numbers[i])) {
                    NumberRowView(number: numbers[i])
                }
                .id(i)
            }
        }
        .add(SearchBar(searchText: $numberState.searchText))
        .onReceive(downloadCompletePublisher) { notification in
            print("dataDownload complete (FilteredPurchasesView 1)")
            if let info = notification.userInfo as? [DataSources.Source:Int], let purchaseCount = info[DataSources.Source.purchased] {
                if purchaseCount > 0 {
                    // now the view can be updated/redrawn
                } else {
                    print("purchase update count = 0")
                }
            }
        }
        .onReceive(publisher) { notification in
            print("dataDownload complete (FilteredPurchasesView 2)")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

关于此的一些注意事项:

  1. 在前几次尝试期间,FilteredPurchasesView 尚未初始化。这意味着没有订阅者来监听已发布的通知。
  2. 两个发布者变量都可用。截至撰写本文时,我无法解释它们为何或如何工作。
  3. 两个onReceive()修饰符都包含通知。

欢迎评论、想法和反馈。