3

Delegates and delegation exist to enable passing specific messages to an observer, regardless of that observer's type. In a coordinator-type architecture, where coordinators manage and run the flow of an application (instead of say the UI layer, à la iOS & UIKit), delegation serves as the primary means of communication between child coordinators and their parents. The problem is that these delegate calls are generally quite specific to the application in question.

A typical example might look like:

protocol AuthenticationCoordinatorDelegate {
    func coordinatorDidPressLoginButton()
    func coordinatorDidPresentAuthenticationPage()
}

This protocol only applies to the authentication coordinator and is only ever implemented by its owner. It's a very specific use case used in one place and because every other coordinator needs a way to communicate, boilerplate runs rampant. The larger an application grows, the more coordinators will exist, and the more one-off delegation interfaces will have to be created, all non-generic.

What are some possible alternatives to the delegation pattern that allows for blind messaging passing between components? One thought I had was a Redux style architecture where instead of informing a delegate something has happened, an action is dispatched to a central store and the parent coordinator reacts appropriately. There are of course, severe limitations to that pattern such as how to model actions like pressing a button in the state tree, and how to persist that state tree (specifically on mobile).

Anyone have suggestions or ideas?

jscs
  • 828
  • 9
  • 17
barndog
  • 131
  • 5
  • 3
    Is it Apple inventing its own non-standard terminology again or simply me being ignorant? I know that "protocol" is their weird new name for 'interface', but what is "coordinator"? Is it a viewmodel? What is "Redux style architecture", is it a new name for the Mediator pattern? What is "state tree"? Thanks. – Den Aug 18 '16 at 08:23
  • Does that language require that the delegate's methods be named the same as the delegator's for the pattern to work? Cannot the delegator call a delegate's method named, say `doExecuteX()` when the login button is pressed? – Tulains Córdova Aug 18 '16 at 11:55
  • I read the [Delegate](https://en.wikipedia.org/wiki/Delegation_pattern) but my mind, doing so, creates an image for an [Observer](https://en.wikipedia.org/wiki/Observer_pattern) instead. So I'm a bit confused. Note that some languages like C# will use the keyword _delegate_ to implement part of the Observer pattern, perhaps it could explain it. Add a tag for the specific language you are using, it would provide some context. – Newtopian Aug 18 '16 at 13:36
  • 1
    Sorry ya'll, here are some clarifications – barndog Aug 18 '16 at 16:09
  • @Den, here's a good link explaining the coordinator pattern https://redbooth.com/engineering/javascript/the-coordinator-pattern. Redux is a web application architecture, dealing with immutable state and a uni-directional data flow. – barndog Aug 18 '16 at 16:10
  • @Tulains Cordova, no they don't, that's just the example I was using. – barndog Aug 18 '16 at 16:10
  • 1
    @Newtopian I am using Swift, so I added that tag, but I was speaking more generally. I understand the confusion so hopefully my previous clarifications help. – barndog Aug 18 '16 at 16:10
  • @startupthekid I think you need to look in the direction of having something like ```protocol CoordinatorDelegate { func coordinatorDidAcceptMessage(T message) }``` and ```protocol Message {}``` and take it from there. It's sad that Swift/JS are trying to reinvent the wheel, it creates an artificial terminology bubble that is annoying to cross. – Den Aug 18 '16 at 16:34
  • 1
    @startupthekid I might be a dinosaur, but if someone forced me to use Swift, I would look into MVVM and Rx: http://blog.scottlogic.com/2015/05/15/mvvm-reactive-cocoa-3.html https://github.com/ReactiveCocoa/ReactiveCocoa – Den Aug 18 '16 at 16:38
  • Agreed @Den, it is pretty annoying. And I love RX and MVVM! It's a fantastic pattern, especially for iOS. I'll give a messages interface a shot, thanks! – barndog Aug 18 '16 at 16:40
  • I think it's similar to the "event listeners" in Java GUI programming. – Tulains Córdova Aug 18 '16 at 16:50
  • ha, ok, so If I understand correctly you are looking for a way to better decouple the _event_ producer from the _event_ consumer in the context of a UI application. In which case, yes indeed, MVVM and/or ReactiveX here can help immensly. If @Den would make that in an answer so he gets proper credits (and my vote) – Newtopian Aug 18 '16 at 17:29
  • Yes please do @Den! I do love RxSwift and MVVM (and RxJS, RxJava, etc, etc). For now at least, that pattern does seem the best way to make message passing at least a bit more generic. – barndog Aug 18 '16 at 21:05

2 Answers2

3

One simple way to provide anonymous linking between components is using closure properties for "notifications".

An object having a name property, for example, might also have:

var didChangeName: ((old: String, new: String) -> Void)?

Upon name being modified, it would call self.didChangeName?(old: oldName, new: newName).

Its owner or another object that was interested in the change -- such as a view in an MVVM setting -- would have set this property earlier to take whatever action was appropriate:

viewModel.didChangeName = { [weak self] (old, new) in
    self?.reactToNameChange(old, new)
}

This is quite flexible in that a) any other object can do whatever it likes with the notifications; b) that object does not have to deal with any notifications that it does not care about*; and c) though probably rarely needed, separate objects can freely register for different portions of the notification set: this is impossible with the traditional delegate setup.

On the other hand, it's a bit less flexible than a solution like KVO/Rx because only one object can "subscribe" to each closure. Also, passing notifications up a control chain is completely explicit, requiring you to link callbacks by hand at each level. For example:

// Parent object
viewModel.modelDidChange = { [weak self] in
    self?.handleModelChange()
}

// Child object
subViewModel.didChangeName = { [weak self] (old, new) in
    // Do things...
    self?.modelDidChange()
}

A second advantage is that it's extremely testable, because there is no requirement for a client other than that it has set the closure:

func testNotifiesViewOnNameChange()
{
    let newName = Model.dummy.name
    var viewModel = ViewModel(model: Model.dummy)
    var sentDidUpdate = false
    viewModel.didUpdate = { sentDidUpdate = true }

    viewModel.name = newName

    XCTAssertTrue(sentDidUpdate)
}

If you're interested in seeing this in more depth, you should have a look at Ian Keen's article on Non-reactive MVVM and the accompanying project on GitHub. That's where I learned about this technique, and I think it's an excellent explanation.


*Not possible with a strictly-Swift protocol

jscs
  • 828
  • 9
  • 17
1

Well, a simple "pattern" that comes to mind is using NSNotificationCenter, something that can come handy when there is a need to update view controllers not directly connected or in cases where you need to update multiple observers at once. Be sure to remove your observers to prevent retain cycles.

Eneko Alonso
  • 374
  • 2
  • 5
  • `NSNotificationCenter` is a very messy pattern to use though, mostly because it's not strongly typed, retain cycles popup everywhere, and it uses a singleton instance of `defaultCenter`, which is never a good idea. – barndog Aug 25 '16 at 21:16
  • 1
    Notifications have far too many capabilities since any part of the application can listen to any other part of the application, even parts that aren't necessarily related whereas the components should have clear separation of concern and responsibility. – barndog Aug 25 '16 at 21:17