1

So basically I have a struct

struct MyStruct {
    var foo : String = "" 
    var bar : String = ""
}

Now I want to do the following : Observe change in an RxVariable of MyStruct, so that whenever that variable is changed, we also have an observer to that variable, we will be able to get the new struct in that observer.

To be clear once again -

Class A

var stct : Variable<MyStruct>() // RxSwift variable

Class B :

 let observer = instanceClassA.stct.asObserver().subscribe(onNext : 
  {(newStruct) in 
       // newStruct found here -
  }
 observer.dispose(by:disposeBag)

The reason I want this flow is : I want Class B to know when Class A's variable of myStruct has changed with new values, as everytime myStruct variable changes, foo and bar, will also change

Think it like Class B is an observer to Class A's variable of myStruct. Now I am learning RxSwift hence I want to utilise its reactive nature of approach. Also I think this is a fairly easy thing to do, but the problem is that I cannot make a Variable (read : Rx) of MyStruct

P.S - I am using Swift 4.0 and RxSwift's latest version.

Any Help is highly appreciated.

Saheb Roy
  • 5,899
  • 3
  • 23
  • 35
  • Is stct variable is being assigned with a complete new instance of struct or you are only modifying the value of foo and bar property of existing stct instance – Sandeep Bhandari Jan 04 '18 at 11:23
  • Can be both, depending on certain logic, is it possible to observe both changes from the same api? – Saheb Roy Jan 04 '18 at 11:24
  • Take a look at this https://stackoverflow.com/questions/36460542/simple-observable-struct-with-rxswift – Sandeep Bhandari Jan 04 '18 at 11:26
  • you can add observer for the values of foo and bar and then use scan to combine the two observers and create a new observable to which you can subscribe. As a result no matter whether you change foo or bar your subscriber will be triggered :). Finally change the MyStruct to class to observe the change by assigning new instance of MyStruct – Sandeep Bhandari Jan 04 '18 at 11:27
  • I have already seen this but this in turns takes the variable inside the struct as an observable, but i want the whole struct variable to be observed – Saheb Roy Jan 04 '18 at 11:28
  • Declare MyStruct as class not as Struct. Structs are passed by value and not by reference where as classes are passed by reference – Sandeep Bhandari Jan 04 '18 at 11:28
  • What if the class/struct has many number of variables, add observers for each one of them using && operator? Surely there must be a way to encapsulate the whole instance as a whole and look for change on it as a whole – Saheb Roy Jan 04 '18 at 11:30
  • post your question here https://rxswift.slack.com/messages/C051G5Y6T/convo/C051G5Y6T-1515062228.000208/ community people are very active here and will help you out – Sandeep Bhandari Jan 04 '18 at 11:35

1 Answers1

0

Why don't you use distinctUntilChanged operator?

You can make your struct conform to Equatable and distinctUntilChanged operator will work this way:

struct MyStruct: Equatable {

    var foo : String = ""
    var bar : String = ""

    static func ==(lhs: MyStruct, rhs: MyStruct) -> Bool {
        return lhs.bar == rhs.bar && lhs.foo == rhs.foo
    }
}

func observableStctChangedByEquatable() -> Observable<MyStruct> {
    return stct
        .asObservable()
        .distinctUntilChanged()
}

let observer = instanceClassA
    .observableStctChangedByEquatable()
    .subscribe(onNext: { (newStruct) in
        //
    })

If you don't like Equatable there are some other ways to use distinctUntilChanged operator. Pick the one you like the most:

struct MyStruct {

    var foo : String = ""
    var bar : String = ""

    static func comparer(lhs: MyStruct, rhs: MyStruct) throws -> Bool {
        return lhs.bar == rhs.bar && lhs.foo == rhs.foo
    }
}

func observableStctChangedByComparer() -> Observable<MyStruct> {
    return stct
        .asObservable()
        .distinctUntilChanged(MyStruct.comparer)
}

func observableStctChangedByBlock() -> Observable<MyStruct> {
    return stct
        .asObservable()
        .distinctUntilChanged({ (lhs, rhs) -> Bool in
            return lhs.bar == rhs.bar && lhs.foo == rhs.foo
        })
}

func observableStctChangedWith(comparer: @escaping (MyStruct, MyStruct) throws -> Bool) -> Observable<MyStruct> {
    return stct
        .asObservable()
        .distinctUntilChanged(comparer)
}

let observer = instanceClassA
    .observableStctChangedWith(comparer: { (lhs, rhs) -> Bool in
        return lhs.bar == rhs.bar && lhs.foo == rhs.foo
    })
    .subscribe(onNext: { (newStruct) in
        //
    })
iWheelBuy
  • 5,470
  • 2
  • 37
  • 71