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?

  • 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 8: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
  • 1
    Sorry ya'll, here are some clarifications – barndog Aug 18 '16 at 16:09
  • 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
  • 1
    @startupthekid I might be a dinosaur, but if someone forced me to use Swift, I would look into MVVM and Rx: blog.scottlogic.com/2015/05/15/mvvm-reactive-cocoa-3.html github.com/ReactiveCocoa/ReactiveCocoa – Den Aug 18 '16 at 16:38
2

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

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.

  • 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.