Search code examples
swiftmvvmreactivekit

Bond/ReactiveKit - Temporarily suspend observing events and start observing again (but see events that were missed)


I'm starting to use Bond to implement a basic MVVM pattern in an app and have a scenario where I would like to temporarily suspend the observing of events on an Observable (via a flag).

I would then like to resume the observing of events, but also want to "replay/resend" the events to my observers which may have been missed during the suspension period.

I have found the pausable(by:) function on an Observable which works well for the temporary suspension of the observing of events, but am not sure how to "replay/resend" any events after reenabling the observation.

An cut-down example of what I'm trying to do is this :-

  • Initially set the value of viewModel.message to be "Original Value"
  • On viewDidLoad bind viewModel.message to the text of label, but allow it to be pausable.
  • On the UI have some buttons that will
    • Change the value of message (changeMessageButton)
    • Stop updating the label text (stopChangingLabelTextButton)
    • Start updating the label text again (startChangingLabelTextButton)

Code :-

class MyViewController: UIViewController {
    let viewModel = MyViewModel()
    let shouldUpdate = Observable(true)

    @IBOutlet weak var label: UILabel!

    @IBOutlet weak var changeMessageButton: UIButton!
    @IBOutlet weak var stopChangingLabelTextButton: UIButton!
    @IBOutlet weak var startChangingLabelTextButton: UIButton!

    override func viewDidLoad() {
       viewModel.message.pausable(by: shouldUpdate).bind(to: label.bnd_text)

       changeMessageButton.bnd_tap.observe { _ in
           viewModel.message.value = "Changing Message"
       }

       stopChangingLabelTextButton.bnd_tap.observe { _ in
           shouldUpdate.value = false
       }

       startChangingLabelTextButton.bnd_tap.observe { _ in
           shouldUpdate.value = true
           // DO SOMETHING TO BE ABLE TO "REPLAY/RESEND" ANY EVENTS TO viewmodel.message 
       }
    }
}

class MyViewModel {
   let message = Observable<String>("Original Value")
}

What would be the best way to tackle this?


Solution

  • Yes, pausable will ignore and omit events during the paused state. If you're ok with replaying only the latest value, you could flat map shouldUpdate like this:

    shouldUpdate.flatMapLatest { shouldUpdate -> SafeSignal<String> in 
        if shouldUpdate {
          return viewModel.message.toSignal()
        } else {
          return .never()
        }
    }.bind(to: label.bnd_text)
    

    Whenever shouldUpdate emits an event, it will either start propagating viewModel.message or nothing. Whenever it starts propagating viewModel.message it will also receive latest value since Observable always replays latests to new observers.

    Please make sure you do import ReactiveKit.