Introducing Swift Action Delegate pattern Part 2
Part two of the Action Delegate pattern: dropping the untyped Any sender and carrying it in the DelegateAction payload instead, so no casting is needed.
Here you find the Part 1 of this article.
A while ago I wrote an article which introduced what I called Swift Action Delegate pattern. It is an attempt to write less boilerplate code while implementing delegation for objects communication.
This was the core (maybe re-read the original article for more context):
protocol DelegateAction {}
protocol ActionDelegate: class {
func actionSender(_ sender: Any, didReceiveAction action: DelegateAction)
}
Few ex-collegues gave me an interesting piece of feedback. The sender is Any type. This is a code smell and not following the Swift principles. We should send an actual type instead, avoiding casting.
Yesterday, I finally figured out how to solve this problem:
protocol DelegateAction {}
protocol ActionDelegate: class {
func actionSender(didReceiveAction action: DelegateAction)
}
We just remove the sender from the function and pass it as part of the DelegateAction payload. If DelegateAction is an enum (as I generally suggest) it can simply be another parameter of its cases.
final class RedViewController: UIViewController {
enum Action: DelegateAction {
case close(sender: RedViewController)
case complete(sender: RedViewController, success: Bool)
}
weak var delegate: ActionDelegate?
func pressButton(sender: Any) {
delegate?.actionSender(didReceiveAction: Action.close(sender: self))
}
}
And the class which conforms to the ActionDelegate protocol, has access to the sender which is of the actual type, not a simple Any type.
final class ParentViewController: UIViewController, ActionDelegate {
func actionSender(didReceiveAction action: DelegateAction) {
switch action {
case RedViewController.Action.close(let sender):
print("Close red. Sender: \(sender)")
case RedViewController.Action.complete(let sender, let success):
print("Complete red. Sender: \(sender). Success: \(success)")
default:
print(action)
}
}
}
I think this makes the ActionDelegate pattern stronger than it used to be.
As always, I am curious to get your opinion and feedback.
Read next
Why Swift protocol conforming values are treated as Value types by default?
An unconstrained Swift protocol makes the compiler treat every conforming value as a value type. Constraining it to classes is what changes that.
Introducing Swift Action Delegate pattern Part 1
Delegation is simple and robust but costs a new protocol per context. The Action Delegate pattern keeps the robustness with far less boilerplate.
How to use Xcode to write Swift code on a remote Linux machine
Mount a headless Linux box over ssh with OSXFuse and SshFS, then edit its Swift code in Xcode on your Mac and compile in a terminal on the machine.