Swift中泛型参数不同时如何赋值

In Swift, how to assign values when generic parameters are different

我正在尝试订阅多个发布者。可能无法确定发布者的输出类型。

static func listen<T>(publisher: Published<T>.Publisher){
    publisher.sink { _Arg in
        // do something
    }.store(in: &cancellables)
}
listen(publisher: env.$showMenuIcon)
listen(publisher: env.$dateFormatLunar)
listen(publisher: env.$dateFormatAd)
listen(publisher: env.$showWeek)
listen(publisher: env.$showWeather)
// in env class
@Published var timeItem = true
@Published var dateFormatAd = "yyyy-MM-dd"

我的每个publisher可能有不同的通用参数类型,我只能这样复制多行代码来调用listen。有没有办法修改 Listen 方法以接受数组类型?或者还有其他方法可以简化我的代码吗?

首先,我建议您不要使用通用函数来订阅不同类型的发布者。为什么?想象一下这是可能的(原则上是可能的,下面是一个例子)。您希望如何区分 sink 块中的不同数据类型?在我看来,将不同的数据类型放在一个屋檐下,然后仍然有可能将它们彼此区分开来的唯一方法是创建您自己的数据类型,这不是通用的。例如。像这样:

struct Result {
    let type: Type   // E.g. an enum of possible types.
    let value: Any
}

然后你必须每次都在你的 sink 块中查找你的值的数据类型并相应地转换它。在我看来,这使您的逻辑非常复杂。我不喜欢通用函数。它们通常是错误的主要来源。

关于如何实现愿望的example/idea:

class MyClass {
    // Common data type
    typealias Value = Any
    
    @Published var numberPublisher: Value?
    @Published var stringPublisher: Value?
    @Published var booleanPublisher: Value?
    
    var subscription: AnyCancellable?
    
    init() {
        // Start listening of publishers.
        listen(publishers: [
            $numberPublisher,
            $stringPublisher,
            $booleanPublisher
        ])
    }
    
    func listen(publishers: [Published<Value?>.Publisher]) {
        let mergedPublishers = Publishers.MergeMany(publishers)

        subscription = mergedPublishers
            // Skipping initial nil values and just not seeing them.
            .dropFirst(publishers.count)
            .sink(receiveCompletion: { completion in
                print("Completion \(completion)")
            }, receiveValue: { value in
                print("Value \(String(describing: value))")
            })
    }
}

正如我在上面所写的,我为所有发布商创建了一个通用数据类型。即使你的函数是泛型的,你也不能同时给它传递不同类型的参数。

我在 Playground 中测试了我的代码:

let myClass = MyClass()
myClass.numberPublisher = 123
myClass.stringPublisher = "ABC"
myClass.booleanPublisher = false

// Console output
Value Optional(123)
Value Optional("ABC")
Value Optional(false)

在你的位置,我会分别直接订阅每个发布者,中间没有任何功能(你已经这样做了)。

希望能帮到你。