Click here to load reader

201710 Fly Me to the View - iOS Conf SG

  • View

  • Download

Embed Size (px)

Text of 201710 Fly Me to the View - iOS Conf SG

  • Fly Me to the View

    Jorge D. Ortiz-Fuentes @jdortiz

  • A Canonical Examples Production

  • #AdvArchMobile

    AgendaArchitecture & Responsibilities

    A modular solution


    XIBs only



  • Persistance FW




    Location FW


    Entity Gateway

    Clean Architecture



  • Wheres the beef?navigation

  • #AdvArchMobile


    Events vs Semantics

    Storyboard vs Decoupled VC

    And without storyboards?

    Dependency Injection

    Memory Management

  • Responsibilities

  • MVP

  • #AdvArchMobile


    Known by its beautiful face and its passivity

    Receives the events and passes them to the presenter

    Knows how to navigate

  • #AdvArchMobile


    Provides meaning to the user events

    Tells the view what to update

    Knows when and where to navigate

  • #AdvArchMobile


    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


    View (VC) Presenter Interactor Entity Gateway


    1 23


  • Segue from VC

  • #AdvArchMobile

    View Controller: Events

    @IBAction func add(_ sender: UIBarButtonItem) { presenter.addButtonTapped()}

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 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 = 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


    View (VC) Presenter Interactor Entity Gateway


    1 2

  • Passing parameters

  • #AdvArchMobile

    Having the Information

    Perform segue & prepare for segue are disconnected

    Information for injection:

    Use sender: DONT

    State in View Controller

    State in Presenter (preferred)

  • XIBs only

  • #AdvArchMobile


    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


    func addButtonTapped() { if abSelector.isA { view.navigateToAddProgrammerA() } else { view.navigateToAddProgrammerB() }}

  • #AdvArchMobile

    RecapNavigation is a key part of an advanced



    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

Search related