Upload
jorge-ortiz
View
198
Download
2
Embed Size (px)
Citation preview
Fly Me to the View
Jorge D. Ortiz-Fuentes @jdortiz
A Canonical Examples Production
#AdvArchMobile
Agenda★Architecture & Responsibilities
★A modular solution
• Storyboards
• XIBs only
★Benefits
★Recap
Persistance FW
View
Netw
ork
Location FW
Presenter
Entity Gateway
Clean Architecture
Interactor
Entity
Where’s the beef?navigation
#AdvArchMobile
Navigation
★Events vs Semantics
★Storyboard vs Decoupled VC
★And without storyboards?
★Dependency Injection
★Memory Management
Responsibilities
MVP
#AdvArchMobile
View
★Known by its beautiful face and its passivity
★Receives the events and passes them to the presenter
★Knows how to navigate
#AdvArchMobile
Presenter
★Provides meaning to the user events
★Tells the view what to update
★Knows when and where to navigate
#AdvArchMobile
Connector
★Knows the dependencies and how to connect them
★Takes you to the next connector
What about MVVM?
#AdvArchMobile
No worries
★MVP ⇒ Tells
★MVVM ⇒ Notifies
★ Feel free to embrace & extend
A modular solution
Decoupling
#AdvArchMobile
View controller
★Separate event from semantics
★Still, navigation is done here
A new VC
View (VC) Presenter Interactor Entity Gateway
Connector
View (VC) Presenter Interactor Entity Gateway
Connector
1 23
4
Segue from VC
#AdvArchMobile
View Controller: Events
@IBAction func add(_ sender: UIBarButtonItem) { presenter.addButtonTapped()}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { presenter.select(row: indexPath.row)}
#AdvArchMobile
Presenter: Navigation Semantics
func addButtonTapped() { view.navigateToAddProgrammer()}
func select(row: Int) { if row < 0 !|| row !>= programmers.count { selectedId = nil } else { let programmer = programmers[row] selectedId = programmer.id view.navigateToProgrammerDetail() }}
#AdvArchMobile
View Controller: Navigation
func navigateToAddProgrammer() { performSegue(withIdentifier: SegueIdentifier.addProgrammer, sender: self)} func navigateToProgrammerDetail() { performSegue(withIdentifier: SegueIdentifier.showProgrammer, sender: self)}
#AdvArchMobile
View Controller: Delegate DI
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let identifier = try! segueIdentifier(for: segue) switch identifier { case .addProgrammer: connector.prepareAddProgrammer(viewController: segue.destination) case .showProgrammer: connector.prepareProgrammerDetail(viewController: segue.destination, presenter: presenter) }}
#AdvArchMobile
Child Connector: Assemble
func assembleModule(view: ProgrammerEditViewController) { let presenter = ProgrammerEditPresenter(otherDep: depencency) view.presenter = presenter view.connector = self presenter.view = view}
#MobAppArch
Implementing navigation and back
★Navigation destination is NOT decided by the view event
★When presented modally, navigation back requires Unwind segue
★ In a navigation controller things happen naturally
Memory Management
Dismiss a VC
View (VC) Presenter Interactor Entity Gateway
Connector
View (VC) Presenter Interactor Entity Gateway
Connector
1 2
Passing parameters
#AdvArchMobile
Having the Information
★Perform segue & prepare for segue are disconnected
★ Information for injection:
• Use sender: DON’T
• State in View Controller
• State in Presenter (preferred)
XIBs only
#AdvArchMobile
Differences
★Easier to pass the information
★Easier to do the injection: Initializer instead of property
★Presentation is done by the source
★No “big picture” or unwind segues
#AdvArchMobile
VC Injection via Initializer
var presenter: ProgrammerEditPresenter
init(presenter: ProgrammerEditPresenter, nibName: String? = nil, bundle: Bundle? = nil) { self.presenter = presenter super.init(nibName: nil, bundle: nil) presenter.view = self}
#AdvArchMobile
Passing Information & Presentation
func navigateToDetail(parameter: String) { let detailViewController = connector.prepareProgrammerDetail(parameter: parameter) navigationController!?.pushViewController(detailViewController, animated: true)}
Benefits
Modify Dependency Injection
#AdvArchMobile
Dependencies Change
★Create them in the connector
★Pass them from one connector to the next
Testable
#AdvArchMobile
Test Everythingfunc testSegueToAddProgrammerInvokesConnectorToNavigate() { let connectorMock = ProgrammersListConnectorMock(some Dep: DepTestDummy()) sut.connector = connectorMock
sut.performSegue(withIdentifier: ProgrammersTableViewControllerMock.SegueIdentifier.addProgrammer, sender: sut)
XCTAssertEqual(1, connectorMock.prepareAddProgrammerInvoked)}
A/B Testing
#AdvArchMobile
Presenter
func addButtonTapped() { if abSelector.isA { view.navigateToAddProgrammerA() } else { view.navigateToAddProgrammerB() }}
#AdvArchMobile
Recap★Navigation is a key part of an advanced
architecture:
• Modular
• Allows passive view
• Not bound to implementation (storyboards)
★Easy to implement & maintain
★Clear benefits
– Anonymous iOS developer
“Fly me to the View Let me play among the Apps”
Thank You!
谢谢
Terima kasih!
ந"#
@jdortiz #AdvArchMobile