简体   繁体   中英

Transform delegate callbacks to SignalProducer events?

I have an object that is a delegate. There are 6 delegate callbacks informing the delegate about the state of things. I have a MySpecialEvent swift enum that represents these states. Can you help me figure out how to correctly initialise a SignalProducer<MySpecialEvent, NoError> and hook the delegate calls to Producer next Events when I instantiate this delegate object?

My expectation is (correct me pls if this is wrong) that the signal producer will be a public producer property of the delegate object. Then I can get a reference to this producer, pass it around and basically handle events elsewhere in reactive fashion.

Initially I though that I could have a MutableProperty on the delegate object, I would change it's value inside each delegate call, and this is giving me a producer for free which I then can observe.

UPDATE: I tried this and it actually works.

But conceptually I don't like this because what I am talking about is events, not persistent state values. It's true it's an implementation detail but still. Is that approach right?

What I try to do with Functional Reactive Programming in general is remove the use of Delegates as much as possible. You are right that it seems a bit more stateful to add a MutableProperty to the delegate class. MutableProperties are kind of a bridge between the stateless and stateful paradigms.

So, what does this mean?

Instead of creating a delegate to use for handling events when things change. Find a way to observe the events as Signals and react to events. An example is probably easiest to understand.

Say you have a modal view that you are presenting, and the presenting controller is the delegate of the presented view controller. You pass the presenting controller to the modal...

func showModal() {
  let modalVC = ModalViewController()
  modalVC.delegate = self
  self.presentModalViewController(modalVC, animated: true)
}

func modalComplete() {
  self.dismissViewControllerAnimated(true, completion: nil)
  print("All Done with Modal.")
}

Then, the presented controller at some point (obviously not showing all the delegate protocol stuff)

func allDone() {
  self.delegate?.modalComplete()
}

The FRP way

Replacing the delegate pattern with FRP would result is something like...

func showModal() {
  let modalVC = ModalViewController()
  modalVC.completionSignal
    .startWithNext { [weak self] _ in
      self.modalComplete()
    }
  self.presentModalViewController(modalVC, animated: true)
}

func modalComplete() {
  self.dismissViewControllerAnimated(true, completion: nil)
  print("All Done with the FRP Modal.")
}

And in your modal you would create a signal you could send something on when it's time to close the modal.

let (completionSignal, completionObserver) = SignalProducer<String, NoError>.buffer(1)

func allDone() {
  completionObserver.sendNext("Whatever you want")
  completionObserver.sendComplete()
}

Hope this helps. Working with both delegates and FRP can get confusing, and one of the things I like best about RAC4 is its ability to replace this cumbersome pattern.

You can also use a true Signal rather than a SignalProducer by defining in the modal view controller like

let (completionSignal, completionObserver) = Signal<String, NoError>.pipe()

And then just observing it on the parent view controller rather than starting and observing it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM