Skip to content

iOS VPN: ViewController Architecture Problem #139

Description

@ailinykh

I made a review of the iOS App and there are some thoughts I would like to share with the community.

The ViewController is responsible for a lot of things:

  • UI updates
  • network extension configuration
  • network extension state management
  • observing application lifecycle events
  • observing network state

This approach violates the Single Responsibility Principle and can lead to a Massive View Controller problem.

Let's see more precisely a ViewController call order:

graph TD
    A[viewDidLoad] -->|animated:false| B(updateLayout)
    A --> C[update]
    L[toggleTapped] --> E
    L -->|animated:true| B
    M[monitor.pathUpdateHandler] --> C
    A --> D{toggleState}
    D -->|true| E[stateChanged]
    A --> F[wormhole.ListenMessage]
    F --> G[updateStatistic]
    C -->|loadAllFromPreferences| B
    E -->|loadAllFromPreferences| C
    E --> H[enforceState]
    H --> I{toggleState}
    I -->|true| J[startVPNTunnel]
    I -->|false| K[stopVPNTunnel]
    N[foreground] --> E
    subgraph Application Lifecycle Events
        A
        N
    end
    subgraph  External Network and User Touch Events
        L
        M
    end
    subgraph  UI Updates
        B
        C
        G
    end
Loading

You can see that some functions are calling another multiple times:

  • ViewDidLoad -> updateLayout
  • ViewDidLoad -> update -> NETunnelProviderManager.loadAllFromPreferences -> updateLayout

or stateChanged invokes NETunnelProviderManager.loadAllFromPreferences and in the callback block, the update method also invokes the NETunnelProviderManager.loadAllFromPreferences

This can lead to some wired UI bugs like so:

new-node-bug.mp4

Solution

I suggest applying a Separation of concerns design principle and splitting ViewController to 4 components:

  • NetworkExtensionManager (holds all the networking stuff, can be divided into small pieces in the future)
  • ViewModel (contains all the business logic)
  • ViewController (responsible for UI and application lifecycle updates only)
  • Presenter (navigation between screens)

I can implement all of this, but I need the approval of the maintainers to make sure we have the same view of things.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions