Delegateless
Coordinators
Ou ainda… Event Based Coordinators
SUMÁRIO
Conteúdo
●Problemas do MVC
●Introdução aos Coordinators
●Delegation
●Solução Base
●Chain of Responsibility
●Delegateless Coordinators
Problemas do
MVC
Problemas do MVC
Responsabilidades
Dependency Injection
Navigation Flow
• Layout
• Model-View binding
• Subview management
• User Input/Interaction
• Data
• Fetching
• Transformation
• Persistency
• Error Handling
• Navigation Flow
Problemas do MVC
Responsabilidades
Dependency Injection
Navigation Flow
• Core Data/Realm
• Network
• Cache
• SomethingManager
• Frameworks de DI
• Typhon
• Kraken
• Perform
• SwiftDependencyInjection
• Swinject
Problemas do MVC
Responsabilidades
Dependency Injection
Navigation Flow
Problemas do MVC
Responsabilidades
Dependency Injection
Navigation Flow
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier !== "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let object = fetchedResultsController.object(at: indexPath)
let controller = (segue.destination as! UINavigationController)
.topViewController as! DetailViewController
controller.detailItem = object
controller.navigationItem
.leftBarButtonItem = splitViewController!?.displayModeButtonItem
controller.navigationItem
.leftItemsSupplementBackButton = true
}
}
}
Introdução aos
Coordinators
So what is a coordinator?
The Coordinator is a PONSO, like all great objects. For
something like Instagram’s photo creation flow, we could
have a PhotoCreationCoordinator. The app
coordinator could spawn a new one, and pass it the
root view controller so that it could present the first
view controller in the flow.
The Coordinator

(Soroush Khanlou)
So what is a coordinator?
A coordinator is an object that bosses one or more view
controllers around. Taking all of the driving logic out of
your view controllers, and moving that stuff one layer
up is gonna make your life a lot more awesome.
Coordinators Redux
(Soroush Khanlou)
Estrutr
Delegation
Delegation
Delegation is a way to make composition as powerful for reuse as inheritance.
In delegation, two objects are involved in handling a request: a receiving object
delegates operations to its delegate. This is analogous to subclasses deferring
requests to parent classes. But with inheritance, an inherited operation can
always refer to the receiving object through the this member variable in C++
and self in Smalltalk. To achieve the same effect with delegation, the receiver
passes itself to the delegate to let the delegated operation refer to the receiver.
Delegation: Super Máquina e RoboCop
Let’s start with a story: Once upon a time, there was a man with no name.
Knight Industries decided that if this man were given guns and wheels and
booster rockets, he would be the perfect crime-fighting tool. First they
thought, “Let’s subclass him and override everything we need to add the
guns and wheels and booster rockets.” The problem was that to subclass
Michael Knight, they needed to wire his insides to the guns, wheels, and
booster rockets – a time-consuming task requiring lots of specialized
knowledge. So instead, Knight Industries created a helper object, the
Knight Industries 2000, or “KITT,” a well-equipped car designed to assist
Michael Knight in a variety of crime- fighting situations.
Delegation: Super Máquina e RoboCop
While approaching the perimeter of an arms dealer’s compound, Michael
Knight would say, “KITT, I need to get to the other side of that wall.” KITT
would then blast a big hole in the wall with a small rocket. After destroying
the wall, KITT would return control to Michael, who would charge through
the rubble and capture the arms dealer.
Note how creating a helper object is different from the RoboCop
approach. RoboCop was a man subclassed and extended. The RoboCop
project involved dozens of surgeons who extended the man into a fighting
machine. This is the approach taken by many object-oriented frameworks.
Delegation: Super Máquina e RoboCop
In the Cocoa framework, many objects are extended in the Knight
Industries way – by supplying them with helper objects. In this section, you
are going to provide the speech synthesizer with a type of helper object
called a delegate.
From Cocoa Programming for OS X: The Big Nerd Ranch Guide
MVC-C · Injecting
Coordinator pattern in
UIKit
Taking the first step towards clean and minimal
app architecture in iOS app means freeing your
view controllers from the burden of dealing with
other controllers.
Implementação extension UIViewController {
private struct AssociatedKeys {
static var ParentCoordinator = "ParentCoordinator"
}
public weak var parentCoordinator: Coordinating? {
get {
return objc_getAssociatedObject(self,
&AssociatedKeys.ParentCoordinator) as? Coordinating
}
set {
objc_setAssociatedObject(self,
&AssociatedKeys.ParentCoordinator,
newValue,
.OBJC_ASSOCIATION_ASSIGN)
}
}
}
View Controller
UIResponder
UIEvent
Filhos de UIResponder
Documentação
Implementação extension UIResponder {
public var coordinatingResponder: UIResponder? {
return next
}
}
extension UIResponder {
func messageTemplate(args: Whatever, sender: Any?) {
coordinatingResponder!?.messageTemplate(args: args, sender: sender)
}
}
extension UIResponder {
func cartBuyNow(_ product: Product, sender: Any?) { … }
func cartAdd(product: Product, color: ColorBox,
sender: Any?, completion: @escaping (Bool, Int) !-> Void) { … }
}
View Controller
UIResponder
UIEvent
Filhos de UIResponder
Documentação
Implementação
Responder objects—that is, instances of UIResponder—
constitute the event-handling backbone of a UIKit app.
Many key objects are also responders, including the
UIApplication object, UIViewController objects, and all
UIView objects (which includes UIWindow). As events
occur, UIKit dispatches them to your app's responder
objects for handling.
View Controller
UIResponder
UIEvent
Filhos de UIResponder
Documentação
Implementação
In addition to handling events, UIKit responders also
manage the forwarding of unhandled events to other
parts of your app. If a given responder does not
handle an event, it forwards that event to the next
event in the responder chain. UIKit manages the
responder chain dynamically, using predefined rules to
determine which object should be next to receive an
event. For example, a view forwards events to its
superview, and the root view of a hierarchy forwards
events to its view controller.
View Controller
UIResponder
UIEvent
Filhos de UIResponder
Documentação
Implementação
View Controller
UIResponder
UIEvent
Filhos de UIResponder
Documentação
Implementação
View Controller
UIResponder
UIEvent
Filhos de UIResponder
Documentação
Implementação
View Controller
UIResponder
UIEvent
Filhos de UIResponder
Documentação
Implementação
View Controller
UIResponder
UIEvent
Filhos de UIResponder
Documentação
Implementação
View Controller
UIResponder
UIEvent
Filhos de UIResponder
Documentação
Implementação
•open class UIView : UIResponder
•open class UIViewController : UIResponder
•open class UIWindow : UIView
•class AppDelegate: UIResponder
•open class UIApplication : UIResponder
View Controller
UIResponder
UIEvent
Filhos de
UIResponder
Documentação
Chain of
Responsibility
Chain-of-Responsibility
In object-oriented design, the chain-of-responsibility pattern is a design pattern
consisting of a source of command objects and a series of processing objects.
Each processing object contains logic that defines the types of command
objects that it can handle; the rest are passed to the next processing object in
the chain. A mechanism also exists for adding new processing objects to the end
of this chain. Thus, the chain of responsibility is an object oriented version of
the if ... else if ... else if ....... else ... endif idiom, with the benefit that the
condition–action blocks can be dynamically rearranged and reconfigured at
runtime.
Delegateless
Coordinators
Nossa solução
There are several kinds of events, including touch
events, motion events, remote-control events, and
press events. To handle a specific type of event, a
responder must override the corresponding
methods. For example, to handle touch events, a
responder implements the touchesBegan(_:with:),
touchesMoved(_:with:), touchesEnded(_:with:), and
touchesCancelled(_:with:) methods. In the case of
touches, the responder uses the event information
provided by UIKit to track changes to those touches
and to update the app's interface appropriately.
Remembering Events
Initial Concept
Defining Events
Protocol
Base implementation
Child management
Event handling
protocol ActionType {}
struct ResponseAction {
var type: ActionType
}
class Action {
private var target: NSObject?
private var selector: Selector?
func addTarget(_ target: NSObject?, action: Selector) {
self.target = target
self.selector = action
}
func send(_ event: Any) {
target!?.perform(selector, with: event)
}
}
Remembering Events
Initial Concept
Defining Events
Protocol
Base implementation
Child management
Event handling
class MyCoodinator: NSObject {
let action: Action
override init() {
action = Action()
super.init()
action.addTarget(self, action: #selector(self.navigate(to:)))
}
@objc func navigate(to destination: Any) {
guard let value = destination as? ResponseAction,
let type = value.type as? HomeType else {
return
}
print(type)
}
}
Remembering Events
Initial Concept
Defining Events
Protocol
Base implementation
Child management
Event handling
protocol AppEventType { }
protocol AppEventSubType { }
protocol AppEvent {
var type: AppEventType { get }
var subtype: AppEventSubType? { get }
}
Remembering Events
Initial Concept
Defining Events
Protocol
Base implementation
Child management
Event handling
protocol CoordinatorProtocol: class {
var identifier: String { get }
var parent: CoordinatorProtocol? { get set }
var childCoordinators: [String: CoordinatorProtocol] { get }
func canProcessEvent(_ event: AppEvent,
withSender sender: Any?) !-> Bool
func target(forEvent event: AppEvent,
withSender sender: Any?) !-> CoordinatorProtocol?
func handleEvent(_ event: AppEvent, withSender: Any?)
func start(with completion: @escaping () !-> Void)
func stop(with completion: @escaping () !-> Void)
func startChild(coordinator: CoordinatorProtocol,
completion: @escaping () !-> Void)
func stopChild(coordinator: CoordinatorProtocol,
completion: @escaping () !-> Void)
}
Remembering Events
Initial Concept
Defining Events
Protocol
Base implementation
Child management
Event handling
class Coordinator: NSObject, CoordinatorProtocol {
weak var parent: CoordinatorProtocol?
var childCoordinators: [String: CoordinatorProtocol] = [:]
weak var rootViewController: UIViewController?
init(rootViewController: UIViewController) {
self.rootViewController = rootViewController
}
func start(with completion: @escaping () !-> Void = {}) {
self.rootViewController!?.parentCoordinator = self
completion()
}
func stop(with completion: @escaping () !-> Void = {}) {
rootViewController!?.parentCoordinator = nil
completion()
}
Remembering Events
Initial Concept
Defining Events
Protocol
Base implementation
Child management
Event handling
func startChild(coordinator: CoordinatorProtocol,
completion: @escaping () !-> Void) {
childCoordinators[coordinator.identifier] = coordinator
coordinator.parent = self
}
func stopChild(coordinator: CoordinatorProtocol,
completion: @escaping () !-> Void = {}) {
coordinator.parent = nil
coordinator.stop { [unowned self] in
self.childCoordinators
.removeValue(forKey: coordinator.identifier)
completion()
}
}
Remembering Events
Initial Concept
Defining Events
Protocol
Base implementation
Child management
Event handling
func canProcessEvent(_ event: AppEvent,
withSender sender: Any?) !-> Bool {
return false
}
func target(forEvent event: AppEvent,
withSender sender: Any?) !-> CoordinatorProtocol? {
guard self.canProcessEvent(event,
withSender: sender) !!= true else {
return self
}
var next = self.parent
while next!?.canProcessEvent(event,
withSender: sender) !!= true {
next = next!?.parent
}
return next
}
func handleEvent(_ event: AppEvent, withSender sender: Any?) {
if self.canProcessEvent(event, withSender: sender) {
!//do something
}
else {
let handler = self.target(forEvent: event,
withSender: sender)
handler!?.handleEvent(event, withSender: sender)
}
}
Remembering Events
Initial Concept
Defining Events
Protocol
Base implementation
Child management
Event handling
DEMO TIME
See here:
https://github.com/talesp/DelegatelessCoordinators
Centro
Av. Presidente Wilson,
231 - 29º andar
(21) 2240-2030
Cidade Monções
Av. Nações Unidas,
11.541 - 3º andar
(11) 4119-0449
Savassi
Av. Getúlio Vargas, 671
Sala 800 - 8º andar
(31) 3360-8900
www.concrete.com.br

Delegateless Coordinator

  • 2.
  • 3.
    SUMÁRIO Conteúdo ●Problemas do MVC ●Introduçãoaos Coordinators ●Delegation ●Solução Base ●Chain of Responsibility ●Delegateless Coordinators
  • 4.
  • 5.
    Problemas do MVC Responsabilidades DependencyInjection Navigation Flow • Layout • Model-View binding • Subview management • User Input/Interaction • Data • Fetching • Transformation • Persistency • Error Handling • Navigation Flow
  • 6.
    Problemas do MVC Responsabilidades DependencyInjection Navigation Flow • Core Data/Realm • Network • Cache • SomethingManager • Frameworks de DI • Typhon • Kraken • Perform • SwiftDependencyInjection • Swinject
  • 7.
  • 8.
    Problemas do MVC Responsabilidades DependencyInjection Navigation Flow override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier !== "showDetail" { if let indexPath = tableView.indexPathForSelectedRow { let object = fetchedResultsController.object(at: indexPath) let controller = (segue.destination as! UINavigationController) .topViewController as! DetailViewController controller.detailItem = object controller.navigationItem .leftBarButtonItem = splitViewController!?.displayModeButtonItem controller.navigationItem .leftItemsSupplementBackButton = true } } }
  • 9.
  • 10.
    So what isa coordinator? The Coordinator is a PONSO, like all great objects. For something like Instagram’s photo creation flow, we could have a PhotoCreationCoordinator. The app coordinator could spawn a new one, and pass it the root view controller so that it could present the first view controller in the flow. The Coordinator
 (Soroush Khanlou)
  • 11.
    So what isa coordinator? A coordinator is an object that bosses one or more view controllers around. Taking all of the driving logic out of your view controllers, and moving that stuff one layer up is gonna make your life a lot more awesome. Coordinators Redux (Soroush Khanlou)
  • 12.
  • 13.
  • 14.
    Delegation Delegation is away to make composition as powerful for reuse as inheritance. In delegation, two objects are involved in handling a request: a receiving object delegates operations to its delegate. This is analogous to subclasses deferring requests to parent classes. But with inheritance, an inherited operation can always refer to the receiving object through the this member variable in C++ and self in Smalltalk. To achieve the same effect with delegation, the receiver passes itself to the delegate to let the delegated operation refer to the receiver.
  • 15.
    Delegation: Super Máquinae RoboCop Let’s start with a story: Once upon a time, there was a man with no name. Knight Industries decided that if this man were given guns and wheels and booster rockets, he would be the perfect crime-fighting tool. First they thought, “Let’s subclass him and override everything we need to add the guns and wheels and booster rockets.” The problem was that to subclass Michael Knight, they needed to wire his insides to the guns, wheels, and booster rockets – a time-consuming task requiring lots of specialized knowledge. So instead, Knight Industries created a helper object, the Knight Industries 2000, or “KITT,” a well-equipped car designed to assist Michael Knight in a variety of crime- fighting situations.
  • 16.
    Delegation: Super Máquinae RoboCop While approaching the perimeter of an arms dealer’s compound, Michael Knight would say, “KITT, I need to get to the other side of that wall.” KITT would then blast a big hole in the wall with a small rocket. After destroying the wall, KITT would return control to Michael, who would charge through the rubble and capture the arms dealer. Note how creating a helper object is different from the RoboCop approach. RoboCop was a man subclassed and extended. The RoboCop project involved dozens of surgeons who extended the man into a fighting machine. This is the approach taken by many object-oriented frameworks.
  • 17.
    Delegation: Super Máquinae RoboCop In the Cocoa framework, many objects are extended in the Knight Industries way – by supplying them with helper objects. In this section, you are going to provide the speech synthesizer with a type of helper object called a delegate. From Cocoa Programming for OS X: The Big Nerd Ranch Guide
  • 18.
    MVC-C · Injecting Coordinatorpattern in UIKit Taking the first step towards clean and minimal app architecture in iOS app means freeing your view controllers from the burden of dealing with other controllers.
  • 19.
    Implementação extension UIViewController{ private struct AssociatedKeys { static var ParentCoordinator = "ParentCoordinator" } public weak var parentCoordinator: Coordinating? { get { return objc_getAssociatedObject(self, &AssociatedKeys.ParentCoordinator) as? Coordinating } set { objc_setAssociatedObject(self, &AssociatedKeys.ParentCoordinator, newValue, .OBJC_ASSOCIATION_ASSIGN) } } } View Controller UIResponder UIEvent Filhos de UIResponder Documentação
  • 20.
    Implementação extension UIResponder{ public var coordinatingResponder: UIResponder? { return next } } extension UIResponder { func messageTemplate(args: Whatever, sender: Any?) { coordinatingResponder!?.messageTemplate(args: args, sender: sender) } } extension UIResponder { func cartBuyNow(_ product: Product, sender: Any?) { … } func cartAdd(product: Product, color: ColorBox, sender: Any?, completion: @escaping (Bool, Int) !-> Void) { … } } View Controller UIResponder UIEvent Filhos de UIResponder Documentação
  • 21.
    Implementação Responder objects—that is,instances of UIResponder— constitute the event-handling backbone of a UIKit app. Many key objects are also responders, including the UIApplication object, UIViewController objects, and all UIView objects (which includes UIWindow). As events occur, UIKit dispatches them to your app's responder objects for handling. View Controller UIResponder UIEvent Filhos de UIResponder Documentação
  • 22.
    Implementação In addition tohandling events, UIKit responders also manage the forwarding of unhandled events to other parts of your app. If a given responder does not handle an event, it forwards that event to the next event in the responder chain. UIKit manages the responder chain dynamically, using predefined rules to determine which object should be next to receive an event. For example, a view forwards events to its superview, and the root view of a hierarchy forwards events to its view controller. View Controller UIResponder UIEvent Filhos de UIResponder Documentação
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
    Implementação •open class UIView: UIResponder •open class UIViewController : UIResponder •open class UIWindow : UIView •class AppDelegate: UIResponder •open class UIApplication : UIResponder View Controller UIResponder UIEvent Filhos de UIResponder Documentação
  • 29.
  • 30.
    Chain-of-Responsibility In object-oriented design,the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain. A mechanism also exists for adding new processing objects to the end of this chain. Thus, the chain of responsibility is an object oriented version of the if ... else if ... else if ....... else ... endif idiom, with the benefit that the condition–action blocks can be dynamically rearranged and reconfigured at runtime.
  • 31.
  • 32.
    There are severalkinds of events, including touch events, motion events, remote-control events, and press events. To handle a specific type of event, a responder must override the corresponding methods. For example, to handle touch events, a responder implements the touchesBegan(_:with:), touchesMoved(_:with:), touchesEnded(_:with:), and touchesCancelled(_:with:) methods. In the case of touches, the responder uses the event information provided by UIKit to track changes to those touches and to update the app's interface appropriately. Remembering Events Initial Concept Defining Events Protocol Base implementation Child management Event handling
  • 33.
    protocol ActionType {} structResponseAction { var type: ActionType } class Action { private var target: NSObject? private var selector: Selector? func addTarget(_ target: NSObject?, action: Selector) { self.target = target self.selector = action } func send(_ event: Any) { target!?.perform(selector, with: event) } } Remembering Events Initial Concept Defining Events Protocol Base implementation Child management Event handling
  • 34.
    class MyCoodinator: NSObject{ let action: Action override init() { action = Action() super.init() action.addTarget(self, action: #selector(self.navigate(to:))) } @objc func navigate(to destination: Any) { guard let value = destination as? ResponseAction, let type = value.type as? HomeType else { return } print(type) } } Remembering Events Initial Concept Defining Events Protocol Base implementation Child management Event handling
  • 35.
    protocol AppEventType {} protocol AppEventSubType { } protocol AppEvent { var type: AppEventType { get } var subtype: AppEventSubType? { get } } Remembering Events Initial Concept Defining Events Protocol Base implementation Child management Event handling
  • 36.
    protocol CoordinatorProtocol: class{ var identifier: String { get } var parent: CoordinatorProtocol? { get set } var childCoordinators: [String: CoordinatorProtocol] { get } func canProcessEvent(_ event: AppEvent, withSender sender: Any?) !-> Bool func target(forEvent event: AppEvent, withSender sender: Any?) !-> CoordinatorProtocol? func handleEvent(_ event: AppEvent, withSender: Any?) func start(with completion: @escaping () !-> Void) func stop(with completion: @escaping () !-> Void) func startChild(coordinator: CoordinatorProtocol, completion: @escaping () !-> Void) func stopChild(coordinator: CoordinatorProtocol, completion: @escaping () !-> Void) } Remembering Events Initial Concept Defining Events Protocol Base implementation Child management Event handling
  • 37.
    class Coordinator: NSObject,CoordinatorProtocol { weak var parent: CoordinatorProtocol? var childCoordinators: [String: CoordinatorProtocol] = [:] weak var rootViewController: UIViewController? init(rootViewController: UIViewController) { self.rootViewController = rootViewController } func start(with completion: @escaping () !-> Void = {}) { self.rootViewController!?.parentCoordinator = self completion() } func stop(with completion: @escaping () !-> Void = {}) { rootViewController!?.parentCoordinator = nil completion() } Remembering Events Initial Concept Defining Events Protocol Base implementation Child management Event handling
  • 38.
    func startChild(coordinator: CoordinatorProtocol, completion:@escaping () !-> Void) { childCoordinators[coordinator.identifier] = coordinator coordinator.parent = self } func stopChild(coordinator: CoordinatorProtocol, completion: @escaping () !-> Void = {}) { coordinator.parent = nil coordinator.stop { [unowned self] in self.childCoordinators .removeValue(forKey: coordinator.identifier) completion() } } Remembering Events Initial Concept Defining Events Protocol Base implementation Child management Event handling
  • 39.
    func canProcessEvent(_ event:AppEvent, withSender sender: Any?) !-> Bool { return false } func target(forEvent event: AppEvent, withSender sender: Any?) !-> CoordinatorProtocol? { guard self.canProcessEvent(event, withSender: sender) !!= true else { return self } var next = self.parent while next!?.canProcessEvent(event, withSender: sender) !!= true { next = next!?.parent } return next } func handleEvent(_ event: AppEvent, withSender sender: Any?) { if self.canProcessEvent(event, withSender: sender) { !//do something } else { let handler = self.target(forEvent: event, withSender: sender) handler!?.handleEvent(event, withSender: sender) } } Remembering Events Initial Concept Defining Events Protocol Base implementation Child management Event handling
  • 40.
  • 41.
    Centro Av. Presidente Wilson, 231- 29º andar (21) 2240-2030 Cidade Monções Av. Nações Unidas, 11.541 - 3º andar (11) 4119-0449 Savassi Av. Getúlio Vargas, 671 Sala 800 - 8º andar (31) 3360-8900 www.concrete.com.br