You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
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.
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:
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 endYou can see that some functions are calling another multiple times:
ViewDidLoad->updateLayoutViewDidLoad->update->NETunnelProviderManager.loadAllFromPreferences->updateLayoutor
stateChangedinvokesNETunnelProviderManager.loadAllFromPreferencesand in the callback block, theupdatemethod also invokes theNETunnelProviderManager.loadAllFromPreferencesThis 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:
I can implement all of this, but I need the approval of the maintainers to make sure we have the same view of things.