首页 > 解决方案 > 使用组合获取枚举发布者

问题描述

如何在 Combine 中获取枚举值的 Publisher?

我想在枚举属性更新以使用组合处理值并为详细说明的值创建新的发布者时收到通知。

我使用硬编码字符串为标签 &co 创建了一个我想要的工作示例。你可以在这里找到https://gist.github.com/alessionossa/543a18a55423d98fc415be9edebbddb5。在这个示例中,我可以简单地使用highlightedPanel没有任何组合代码,但在我的实际项目中,有一个更复杂的逻辑需要使用组合。现在我想使用枚举来识别 NavigationLinks 来完成此操作。

这是代码示例:

import SwiftUI
import Combine

struct ContentView: View {

    enum SectionPane: Equatable, Identifiable, CustomStringConvertible {

        case servers
        case snippets

        var description: String {
            switch self {
            case .servers:
                return "server"
            case .snippets:
                return "snippet"
            }
        }

        var id: SectionPane { self }
    }

    @State var selectedPane: SectionPane? = nil

    // BUG workaround, suggested at https://stackoverflow.com/questions/61003652/selection-in-navigationlink-is-not-working
    @State var highlightedPane: SectionPane? = nil

    // Subscribe to highlightedPane update to update active var
    private var isActivePublisher: AnyPublisher<String, Never> {
        // SPOILER: Value of type 'ContentView.SectionPane' has no member 'publisher'
        return highlightedPane?.publisher
            .map { $0.description }
            .eraseToAnyPublisher() ??
                Just("").eraseToAnyPublisher()
    }

    @State private var active: String = ""

    var body: some View {
        NavigationView {
            VStack(alignment: .leading) {
                // Current selection label
                Text("Selected: \(active)")

                NavigationLink(destination: Text("first view").onAppear{ self.highlightedPane = SectionPane.servers }, tag: SectionPane.servers, selection: $selectedPane) {
                    Text("First")
                }
                NavigationLink(destination: Text("second view").onAppear{ self.highlightedPane = SectionPane.snippets }, tag: SectionPane.snippets, selection: $selectedPane) {
                    Text("Second")
                }

                Spacer()
            }.onReceive(isActivePublisher, perform: { selection in
                self.active = selection
            })
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

标签: swiftswiftuicombine

解决方案


如何让世界更简单,如下所示......

enum SectionPane: Equatable, Identifiable, CustomStringConvertible {

    case servers
    case snippets

    var description: String {
        switch self {
        case .servers:
            return "server"
        case .snippets:
            return "snippet"
        }
    }

    var id: SectionPane { self }
}

class SectionPaneViewModel: ObservableObject {
    @Published var highlightedPane: SectionPane? = nil
    @Published var selectedPane: SectionPane? = nil
}

struct TestEnumPublisher: View {
    @ObservedObject var vm = SectionPaneViewModel()

    @State private var active: String = ""

    var body: some View {
        NavigationView {
            VStack(alignment: .leading) {
                // Current selection label
                Text("Selected: \(active)")

                NavigationLink(destination: Text("first view").onAppear{ self.vm.highlightedPane = .servers },
                            tag: SectionPane.servers, selection: $vm.selectedPane) {
                    Text("First")
                }
                NavigationLink(destination: Text("second view").onAppear{ self.vm.highlightedPane = .snippets },
                            tag: SectionPane.snippets, selection: $vm.selectedPane) {
                    Text("Second")
                }

                Spacer()
            }.onReceive(vm.$selectedPane, perform: { selection in
                self.active = selection?.description ?? "none"
            })
        }
    }
}

推荐阅读