Просмотр исходного кода

Merge pull request #562 from kingst/fix-swinject-thread-safety

Add locking to our Swinject resolver
Deniz Cengiz 11 месяцев назад
Родитель
Сommit
b93ba13753

+ 5 - 1
Trio.xcodeproj/project.pbxproj

@@ -201,6 +201,7 @@
 		38FEF3FC2737E53800574A46 /* MainStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF3FB2737E53800574A46 /* MainStateModel.swift */; };
 		38FEF3FE2738083E00574A46 /* CGMSettingsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF3FD2738083E00574A46 /* CGMSettingsProvider.swift */; };
 		38FEF413273B317A00574A46 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF412273B317A00574A46 /* HKUnit.swift */; };
+		3B0B4E6C2DE1439F005C6627 /* LockedResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B0B4E6B2DE1439A005C6627 /* LockedResolver.swift */; };
 		3B2F77862D7E52ED005ED9FA /* TDD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B2F77852D7E52ED005ED9FA /* TDD.swift */; };
 		3B2F77882D7E5387005ED9FA /* CurrentTDDSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B2F77872D7E5387005ED9FA /* CurrentTDDSetup.swift */; };
 		3B3B57C92DA07B3400849D16 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3B57C82DA07B3400849D16 /* GoogleService-Info.plist */; };
@@ -1035,6 +1036,7 @@
 		38FEF3FB2737E53800574A46 /* MainStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainStateModel.swift; sourceTree = "<group>"; };
 		38FEF3FD2738083E00574A46 /* CGMSettingsProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGMSettingsProvider.swift; sourceTree = "<group>"; };
 		38FEF412273B317A00574A46 /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = "<group>"; };
+		3B0B4E6B2DE1439A005C6627 /* LockedResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockedResolver.swift; sourceTree = "<group>"; };
 		3B2F77852D7E52ED005ED9FA /* TDD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TDD.swift; sourceTree = "<group>"; };
 		3B2F77872D7E5387005ED9FA /* CurrentTDDSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentTDDSetup.swift; sourceTree = "<group>"; };
 		3B3B57C82DA07B3400849D16 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
@@ -2104,8 +2106,9 @@
 			isa = PBXGroup;
 			children = (
 				38E4451D274DB04600EC9A94 /* AppDelegate.swift */,
-				388E595B25AD948C0019842D /* TrioApp.swift */,
 				BD4ED4FC2CF9D5E8000EDC9C /* AppState.swift */,
+				3B0B4E6B2DE1439A005C6627 /* LockedResolver.swift */,
+				388E595B25AD948C0019842D /* TrioApp.swift */,
 			);
 			path = Application;
 			sourceTree = "<group>";
@@ -4258,6 +4261,7 @@
 				3811DE0C25C9D32F00A708ED /* BaseProvider.swift in Sources */,
 				CE95BF5A2BA62E4A00DC3DE3 /* PluginSource.swift in Sources */,
 				DD21FCB52C6952AD00AF2C25 /* DecimalPickerSettings.swift in Sources */,
+				3B0B4E6C2DE1439F005C6627 /* LockedResolver.swift in Sources */,
 				3811DE5C25C9D4D500A708ED /* Formatters.swift in Sources */,
 				3871F39F25ED895A0013ECB5 /* Decimal+Extensions.swift in Sources */,
 				CEE9A6592BBB418300EB5194 /* CalibrationsDataFlow.swift in Sources */,

+ 273 - 0
Trio/Sources/Application/LockedResolver.swift

@@ -0,0 +1,273 @@
+import Foundation
+import Swinject
+
+/// This class adds a simple wrapper around a Swinject resolver to ensure that only one thread can
+/// access it at any given time.
+struct LockedResolver: Resolver {
+    let resolver: Resolver
+    let lock: NSRecursiveLock
+
+    func resolve<Service, Arg1>(_ serviceType: Service.Type, argument: Arg1) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, argument: argument)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1>(_ serviceType: Service.Type, name: String?, argument: Arg1) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, name: name, argument: argument)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2>(_ serviceType: Service.Type, arguments arg1: Arg1, _ arg2: Arg2) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, arguments: arg1, arg2)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2>(
+        _ serviceType: Service.Type,
+        name: String?,
+        arguments arg1: Arg1,
+        _ arg2: Arg2
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, name: name, arguments: arg1, arg2)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3>(
+        _ serviceType: Service.Type,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, arguments: arg1, arg2, arg3)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3>(
+        _ serviceType: Service.Type,
+        name: String?,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, name: name, arguments: arg1, arg2, arg3)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4>(
+        _ serviceType: Service.Type,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, arguments: arg1, arg2, arg3, arg4)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4>(
+        _ serviceType: Service.Type,
+        name: String?,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, name: name, arguments: arg1, arg2, arg3, arg4)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4, Arg5>(
+        _ serviceType: Service.Type,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4,
+        _ arg5: Arg5
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, arguments: arg1, arg2, arg3, arg4, arg5)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4, Arg5>(
+        _ serviceType: Service.Type,
+        name: String?,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4,
+        _ arg5: Arg5
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, name: name, arguments: arg1, arg2, arg3, arg4, arg5)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6>(
+        _ serviceType: Service.Type,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4,
+        _ arg5: Arg5,
+        _ arg6: Arg6
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, arguments: arg1, arg2, arg3, arg4, arg5, arg6)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6>(
+        _ serviceType: Service.Type,
+        name: String?,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4,
+        _ arg5: Arg5,
+        _ arg6: Arg6
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, name: name, arguments: arg1, arg2, arg3, arg4, arg5, arg6)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7>(
+        _ serviceType: Service.Type,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4,
+        _ arg5: Arg5,
+        _ arg6: Arg6,
+        _ arg7: Arg7
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, arguments: arg1, arg2, arg3, arg4, arg5, arg6, arg7)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7>(
+        _ serviceType: Service.Type,
+        name: String?,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4,
+        _ arg5: Arg5,
+        _ arg6: Arg6,
+        _ arg7: Arg7
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, name: name, arguments: arg1, arg2, arg3, arg4, arg5, arg6, arg7)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8>(
+        _ serviceType: Service.Type,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4,
+        _ arg5: Arg5,
+        _ arg6: Arg6,
+        _ arg7: Arg7,
+        _ arg8: Arg8
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, arguments: arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8>(
+        _ serviceType: Service.Type,
+        name: String?,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4,
+        _ arg5: Arg5,
+        _ arg6: Arg6,
+        _ arg7: Arg7,
+        _ arg8: Arg8
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, name: name, arguments: arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9>(
+        _ serviceType: Service.Type,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4,
+        _ arg5: Arg5,
+        _ arg6: Arg6,
+        _ arg7: Arg7,
+        _ arg8: Arg8,
+        _ arg9: Arg9
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, arguments: arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9>(
+        _ serviceType: Service.Type,
+        name: String?,
+        arguments arg1: Arg1,
+        _ arg2: Arg2,
+        _ arg3: Arg3,
+        _ arg4: Arg4,
+        _ arg5: Arg5,
+        _ arg6: Arg6,
+        _ arg7: Arg7,
+        _ arg8: Arg8,
+        _ arg9: Arg9
+    ) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, name: name, arguments: arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service>(_ serviceType: Service.Type) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType)
+        lock.unlock()
+        return service
+    }
+
+    func resolve<Service>(_ serviceType: Service.Type, name: String?) -> Service? {
+        lock.lock()
+        let service = resolver.resolve(serviceType, name: name)
+        lock.unlock()
+        return service
+    }
+}

+ 6 - 5
Trio/Sources/Application/TrioApp.swift

@@ -52,15 +52,16 @@ extension Notification.Name {
         SecurityAssembly()
     ], parent: nil, defaultObjectScope: .container)
 
+    // Simple thread-safe wrapper
+    private static let resolverLock = NSRecursiveLock()
+
     var resolver: Resolver {
-        TrioApp.assembler.resolver
+        TrioApp.resolver
     }
 
-    // Temp static var
-    // Use to backward compatibility with old Dependencies logic on Logger
-    // TODO: Remove var after update "Use Dependencies" logic in Logger
     static var resolver: Resolver {
-        TrioApp.assembler.resolver
+        // Return a simple wrapper that adds locking
+        LockedResolver(resolver: assembler.resolver, lock: resolverLock)
     }
 
     private func loadServices() {