Code Block NETunnelProviderManager:loadAllFromPreferences(completionHandler:)
From the documentation:
As a result of this note, an early implementation I had took a very conservative approach; calling loadFromPreferences(completionHandler:): every time before operating on my NEPacketTunnelProvider. This was done by a helper function which was run as a precursor to any operation done to the manager, ensuring that the latest manager was being used every time. This looked something like:You must call loadFromPreferences(completionHandler:): at least once before calling this method the first time after your app launches.
Code Block func myStartVPN() { loadHelper { (manager: NEPacketTunnelProvider, error: Error?) in /* handle errors */ startVPN(withManager: manager) } }
When using this approach, I noticed that observers that look for NEVPNStatusDidChange events got triggered multiple times for these events, with the number of times it being triggered machine the number of times I called loadAllFromPreferences(). Chronologically speaking I was experiencing something along the lines of Appendix 1.
As a result of this issue, my production equivalent of loadHelper(), above, only calls load once the first time a manager is requied, and then subsequent operations on the manager use a cached value - a bit like a standard lazy field.
Obviously this is not a big issue as I have a working solution, however I haven't been able to work out what causes this behaviour - does anyone have any ideas?
Could it be a general Swift/Objective C pitfall with KVO that I am not aware of?
Could it be some sort of issue with NetworkExtension/my approach? (I'm thinking some references might not be being cleaned up every time I load?)
Appendix 1
Previously set up NEPacketTunnelProvider*
loadAllFromPreferences() followed by saveManager()
Recieve NEVPNStatusDidChange - Disconnected
loadAllFromPreferences() followed by startVPNTunnel()
Recieve NEVPNStatusDidChange - Connecting x2
Recieve NEVPNStatusDidChange - Connected x2
loadAllFromPreferences() followed by stopVPNTunnel()
Recieve NEVPNStatusDidChange - Disconnecting x3
Recieve NEVPNStatusDidChange - Disconnected x3
loadAllFromPreferences() followed by startVPNTunnel()
Recieve NEVPNStatusDidChange - Connecting x4
Recieve NEVPNStatusDidChange - Connected x4
loadAllFromPreferences() followed by stopVPNTunnel()
Recieve NEVPNStatusDidChange - Disconnecting x5
Recieve NEVPNStatusDidChange - Disconnected x5