[Q] How many instances of the same NEFilterDataProvider subclass can there be in a single running Network Extension at any given time?
I would expect that there can be only 1 instance but I'm looking at a memgraph where 2 instances are listed.
As it's the Network Extension framework that is responsible for creating, starting and stopping these instances, this is rather strange.
OK. With a sysex all of your providers will be instantiated within the same process. That can result in multiple instances of a provider showing up. For example:
-
The system creates an instance and starts it.
-
It then stops it. That should release the last reference to the provider object but that’s not guaranteed. More on that below.
-
The system decides it needs your provider running, and so it creates a second instance and starts that.
Regarding step 2, what can cause this instance to persist? Well, in general that’d be caused by a bug, but there’s no guarantee that it’s a system bug:
-
It’s possible that the system has failed to drop a reference.
-
It’s also possible that your code has created its own reference.
Either of these could be a leak, or a circular reference, or abandoned memory [1].
So, two questions:
-
Does your logging show that only one instance is started? If you had two started instances, that’d be super weird.
-
If you explore the memgraph, what’s holding the stopped instance in memory?
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] For an example of how easy this is to get this wrong, consider this code:
class FilterDataProvider: NEFilterDataProvider {
deinit {
self.myEventHandler = nil
}
var myEventHandler: (() -> Void)?
override func handleNewFlow(_ flow: NEFilterFlow) -> NEFilterNewFlowVerdict {
if someCriteria() {
self.myEventHandler = {
… work with `self` …
}
}
return .allow()
}
}
This forms a retain loop if someCriteria()
returns true: The class holds a reference to the myEventHandler
closure and myEventHandler
closure holds a reference to the class.
IMPORTANT Folks often break these sorts of retain loops with the ‘weak self dance’. I’m not a fan of that. In this case you want to break the retain loop by setting myEventHandler
to nil
in stopFilter(…)
.