1

I am trying to define an array of Rxswift Variable which is of different types (Int, String, Bool, String?, etc...)

So technically I want something like this,

var intVariable = Variable<Int>(10)
var stringVariable = Variable<String>("Hello, RxSwift")
let genericArray = [intVariable, stringVariable]

Reason for this is that, I have a list of variables that i want to subscribe on.

However, i can subscribe on the variables individually like intVariable.asObservable().subscribe, stringVariable.asObservable().subscribe and so on. But if its in an array, I could loop through all the elements and subscribe on it.

The Rxswift Variable is defined as public final class Variable<Element>

P.S I have tried type erasure but no luck. Any help on this would be appreciated!

  • I doubt that it is possible? What is the case in which you need to subscribe to variables of different type? – iWheelBuy May 03 '17 at 08:40
  • instead of making a loop to subscribe to each individual observable, I suggest to subscribe once to merged sequence of observables. Since you have different type of variables, you could perform a workaround as described here http://stackoverflow.com/questions/39050059/rxswift-merge-different-kind-of-observables – Nimble May 03 '17 at 11:49
  • Thanks @Nimble, works great for my case. – Bharath Urs May 03 '17 at 17:30

1 Answers1

1

What you do here depends entirely on what that subscribe closure looks like. If you are doing the same thing to every item in either variable, regardless of type then just map them both to the same type:

let bag = DisposeBag()
let intVariable = Variable<Int>(10)
let stringVariable = Variable<String>("Hello, RxSwift")
let genericArray = Observable.merge([intVariable.asObservable().map { "\($0)" }, stringVariable.asObservable()])
genericArray.subscribe(onNext: { print($0) }).disposed(by: bag)
intVariable.value = 5
stringVariable.value = "Goodby, RxSwift"

prints:

10
Hello, RxSwift
5
Goodby, RxSwift

If you are combining the two items in some way where you need the most recent emitted of each variable and you need to keep the type information then do this:

let genericArray = Observable.combineLatest(intVariable.asObservable(), stringVariable.asObservable())

prints:

(10, "Hello, RxSwift")
(5, "Hello, RxSwift")
(5, "Goodby, RxSwift")

If you only want your subscribe to be triggered when a new element is emitted from both variables, then:

let genericArray = Observable.zip(intVariable.asObservable(), stringVariable.asObservable())

which prints:

(10, "Hello, RxSwift")
(5, "Goodby, RxSwift")

I would avoid the solutions mentioned in (RxSwift merge different kind of Observables)

Community
  • 1
  • 1
Daniel T.
  • 32,821
  • 6
  • 50
  • 72
  • Thanks @Daniel T , the problem i saw with `combineLatest` and `zip` is that it is limited to 8 arguments and not generic. I feel the first option (with merge) would be the best option for my case, reason being, i just need to listen for updates and run `invalidateLayout` on any change. – Bharath Urs May 29 '17 at 17:43
  • 1
    They absolutely are generic. If you have more than 8 arguments, the use combines of combines or zips of zips. – Daniel T. May 29 '17 at 17:46