From ba2d10ba6ecaac9bf5857ecd1569d3086bba9e67 Mon Sep 17 00:00:00 2001 From: pwespi Date: Sat, 6 Apr 2024 11:40:08 +0200 Subject: [PATCH] fix(ios): make callback map thread-safe to fix high write and notify rates #630 --- ios/Plugin.xcodeproj/project.pbxproj | 4 ++++ ios/Plugin/Device.swift | 2 +- ios/Plugin/ThreadSafeDictionary.swift | 13 +++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 ios/Plugin/ThreadSafeDictionary.swift diff --git a/ios/Plugin.xcodeproj/project.pbxproj b/ios/Plugin.xcodeproj/project.pbxproj index b234ccaa..98b95b18 100644 --- a/ios/Plugin.xcodeproj/project.pbxproj +++ b/ios/Plugin.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 03FC29A292ACC40490383A1F /* Pods_Plugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2A61DA5A1F2DD4F959604D /* Pods_Plugin.framework */; }; 20C0B05DCFC8E3958A738AF2 /* Pods_PluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6753A823D3815DB436415E3 /* Pods_PluginTests.framework */; }; + 340BC4032BC1A447004AFEFC /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BC4022BC1A447004AFEFC /* ThreadSafeDictionary.swift */; }; 34E541D62962E2EA007544B1 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E541D52962E2EA007544B1 /* Logging.swift */; }; 34ECC0E325BE199F00881175 /* Device.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34ECC0E025BE199F00881175 /* Device.swift */; }; 34ECC0E425BE199F00881175 /* Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34ECC0E125BE199F00881175 /* Conversion.swift */; }; @@ -33,6 +34,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 340BC4022BC1A447004AFEFC /* ThreadSafeDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreadSafeDictionary.swift; sourceTree = ""; }; 34E541D52962E2EA007544B1 /* Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = ""; }; 34ECC0E025BE199F00881175 /* Device.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Device.swift; sourceTree = ""; }; 34ECC0E125BE199F00881175 /* Conversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Conversion.swift; sourceTree = ""; }; @@ -100,6 +102,7 @@ 50ADFF8A201F53D600D50D53 /* Plugin */ = { isa = PBXGroup; children = ( + 340BC4022BC1A447004AFEFC /* ThreadSafeDictionary.swift */, 34E541D52962E2EA007544B1 /* Logging.swift */, 34ECC0E125BE199F00881175 /* Conversion.swift */, 34ECC0E025BE199F00881175 /* Device.swift */, @@ -317,6 +320,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 340BC4032BC1A447004AFEFC /* ThreadSafeDictionary.swift in Sources */, 34ECC0E325BE199F00881175 /* Device.swift in Sources */, 34E541D62962E2EA007544B1 /* Logging.swift in Sources */, 34ECC0E425BE199F00881175 /* Conversion.swift in Sources */, diff --git a/ios/Plugin/Device.swift b/ios/Plugin/Device.swift index 656c7b8e..20650c3f 100644 --- a/ios/Plugin/Device.swift +++ b/ios/Plugin/Device.swift @@ -6,7 +6,7 @@ class Device: NSObject, CBPeripheralDelegate { typealias Callback = (_ success: Bool, _ value: String) -> Void private var peripheral: CBPeripheral! - private var callbackMap = [String: Callback]() + private var callbackMap = ThreadSafeDictionary() private var timeoutMap = [String: DispatchWorkItem]() private var servicesCount = 0 private var servicesDiscovered = 0 diff --git a/ios/Plugin/ThreadSafeDictionary.swift b/ios/Plugin/ThreadSafeDictionary.swift new file mode 100644 index 00000000..9fdad3b7 --- /dev/null +++ b/ios/Plugin/ThreadSafeDictionary.swift @@ -0,0 +1,13 @@ +class ThreadSafeDictionary { + private var dictionary: [K: T] = [:] + private let queue = DispatchQueue(label: "threadSafeDictionaryQueue", attributes: .concurrent) + + subscript(key: K) -> T? { + get { + return queue.sync { dictionary[key] } + } + set { + queue.async(flags: .barrier) { self.dictionary[key] = newValue } + } + } +}