-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Bug Report
Capacitor Version
💊 Capacitor Doctor 💊
Latest Dependencies:
@capacitor/cli: 4.1.0
@capacitor/core: 4.1.0
@capacitor/android: 4.1.0
@capacitor/ios: 4.1.0
Installed Dependencies:
@capacitor/android: not installed
@capacitor/cli: 4.1.0
@capacitor/core: 4.1.0
@capacitor/ios: 4.1.0
[success] iOS looking great! 👌
Platform(s)
iOS
Current Behavior
Calling saveCall
or releaseCall
from another queue other than the "bridge"-DispatchQueue
can cause crashes since Swift's dictionaries are not thread-safe.
Expected Behavior
The expected behaviour would be no crashes. I understand that it may be required that the calls are saved or released on the "bridge"-DispatchQueue
. But there is no possibility to do this from other threads which should be possible in my opinion since you may want to release a call after some asynchronous portion of code is done. getDispatchQueue()
is internal, so there is no way to schedule work on it other than reflection.
Code Reproduction
In the JS portion you literally just do this:
for (let i = 0; i < 10000; i++) {
Capacitor.Plugins.BridgeCrash.echo({value: 'test'});
}
And in the native part:
@objc func echo(_ call: CAPPluginCall) {
call.keepAlive = true
DispatchQueue.main.async { [self] in
bridge?.saveCall(call)
call.resolve([:])
bridge?.releaseCall(call)
}
}
Other Technical Details
npm --version
output:
8.5.2
node --version
output:
v16.13.1
pod --version
output (iOS issues only):
1.11.3
Additional Context
The crash (most of the time) is here:
@objc public func releaseCall(withID: String) {
storedCalls.removeValue(forKey: withID)
}
This makes sense since Swift's dictionaries are not thread-safe and the 10.000 calls was causing race conditions most of the times I tried. I am suggesting to either put a lock around the storedCalls
dictionary access or grant access to the internal DispatchQueue
so you can safely switch to the correct thread.