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.