I would like to create a PassthroughSubject object that can send an output of any type. In code I currently have something like this:
let cmd1Subj = PassthroughSubject<String, Never>()
let cmd2Subj = PassthroughSubject<String, Never>()
var desiredCmd: PassthroughSubject<String, Never>?
let executeDesiredCmdSubj = PassthroughSubject<String, Never>()
var arg: String?
func executeDesiredCmd(cmdArg: String) -> AnyPublisher<String, Never> {
guard (desiredCmd != nil) else {
return Just("Nothing to execute\n").eraseToAnyPublisher()
}
desiredCmd?.send(cmdArg)
return Just("Executed: \(String(describing: desiredCmd)) with argument: \(cmdArg)").eraseToAnyPublisher()
}
let cancellable = executeDesiredCmdSubj
.flatMap(executeDesiredCmd)
.receive(on: DispatchQueue.main)
.sink(receiveValue: {
print($0)
})
desiredCmd = cmd1Subj
arg = "This is the argument for command 1"
desiredCmd?.send(arg!)
desiredCmd = cmd2Subj
arg = "This is the argument for command 2"
desiredCmd?.send(arg!)
How do I change desiredCmd
and executeDesiredCmdSubj
such that they can send an output of any type, as determined at runtime? I'd like to do something like this:
let cmd1Subj = PassthroughSubject<Int, Never>()
let cmd2Subj = PassthroughSubject<String, Never>()
var desiredCmd: PassthroughSubject<Some_Generic_Type, Never>?
let executeDesiredCmdSubj = PassthroughSubject<Some_Generic_Type, Never>()
var arg: Some_Generic_Type?
func executeDesiredCmd(cmdArg: Some_Generic_Type) -> AnyPublisher<String, Never> {
guard (desiredCmd != nil) else {
return Just("Nothing to execute\n").eraseToAnyPublisher()
}
desiredCmd?.send(cmdArg)
return Just("Executed: \(String(describing: desiredCmd)) with argument: \(cmdArg)").eraseToAnyPublisher()
}
let cancellable = executeDesiredCmdSubj
.flatMap(executeDesiredCmd)
.receive(on: DispatchQueue.main)
.sink(receiveValue: {
print($0)
})
desiredCmd = cmd1Subj
arg = 12345
desiredCmd?.send(arg!)
desiredCmd = cmd2Subj
arg = "This is the argument for command 2"
desiredCmd?.send(arg!)
where Some_Generic_Type is a placeholder that can be used to represent any type I attempt to pass through my PassthroughSubject. I tried using "Any" as the placeholder but it produces a couple of compilation errors:
I was able to do this by creating a struct that defines a couple of enums with associated values:
struct VersatilePassthroughSubject {
enum SubjectOutputType {
case subjAsStringOutput(PassthroughSubject<String, Never>)
case subjAsIntOutput(PassthroughSubject<Int, Never>)
}
enum Arg {
case argAsString(String)
case argAsInt(Int)
}
var subj: SubjectOutputType? = nil
var arg: Arg? = nil
}
let cmd1Subj = PassthroughSubject<Int, Never>()
let cmd2Subj = PassthroughSubject<String, Never>()
var desiredCmd: VersatilePassthroughSubject = VersatilePassthroughSubject()
let executeDesiredCmdSubj = PassthroughSubject<Void, Never>()
func executeDesiredCmd() -> AnyPublisher<String, Never> {
guard (desiredCmd.subj != nil) else {
return Just("Nothing to execute\n").eraseToAnyPublisher()
}
if case .subjAsIntOutput(let subj) = desiredCmd.subj {
if case .argAsInt(let arg) = desiredCmd.arg {
subj.send(arg)
return Just("Executed: \(String(describing: desiredCmd)) with argument: \(arg)").eraseToAnyPublisher()
}
}
else if case .subjAsStringOutput(let subj) = desiredCmd.subj {
if case .argAsString(let arg) = desiredCmd.arg {
subj.send(arg)
return Just("Executed: \(String(describing: desiredCmd)) with argument: \(arg)").eraseToAnyPublisher()
}
}
return Just("Nothing to execute\n").eraseToAnyPublisher()
}
let cancellable = executeDesiredCmdSubj
.flatMap(executeDesiredCmd)
.receive(on: DispatchQueue.main)
.sink(receiveValue: {
print($0)
})
desiredCmd.subj = .subjAsIntOutput(cmd1Subj)
desiredCmd.arg = .argAsInt(12345)
executeDesiredCmdSubj.send()
desiredCmd.subj = .subjAsStringOutput(cmd2Subj)
desiredCmd.arg = .argAsString("This is the argument for command 2")
executeDesiredCmdSubj.send()