Skip to content

Commit

Permalink
small improve DICacheStorage - make this thread saved. Fix initialize…
Browse files Browse the repository at this point in the history
…SingletonObjects and initializeObjectsForScope thread safe - now it's correctly work from more threads call. Fix warnings.
  • Loading branch information
Alexander Ivlev committed Apr 27, 2021
1 parent d93c366 commit 6e7189e
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 22 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# v4.2.2
* Improve thread safe for public scopes. Actually only if you use custom lifetime.
* Fix thread safe for methods `initializeSingletonObjects` and `initializeObjectsForScope`

# v4.2.1
* Fix memory leak ParsedType. About bug in comments [#159](https://github.com/ivlevAstef/DITranquillity/issues/159) issue

Expand Down
2 changes: 1 addition & 1 deletion DITranquillity.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|

s.name = 'DITranquillity'
s.version = '4.2.1'
s.version = '4.2.2'
s.summary = 'DITranquillity - Dependency injection for iOS/macOS/tvOS (Swift) '

s.description = <<-DESC
Expand Down
16 changes: 8 additions & 8 deletions DITranquillity.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1220,7 +1220,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.10;
MARKETING_VERSION = 4.2.1;
MARKETING_VERSION = 4.2.2;
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.sia.DITranquillity-OSX";
PRODUCT_NAME = DITranquillity;
Expand Down Expand Up @@ -1260,7 +1260,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.10;
MARKETING_VERSION = 4.2.1;
MARKETING_VERSION = 4.2.2;
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.sia.DITranquillity-OSX";
PRODUCT_NAME = DITranquillity;
Expand Down Expand Up @@ -1301,7 +1301,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.10;
MARKETING_VERSION = 4.2.1;
MARKETING_VERSION = 4.2.2;
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.sia.DITranquillity-tvOS";
PRODUCT_MODULE_NAME = DITranquillity;
Expand Down Expand Up @@ -1344,7 +1344,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.10;
MARKETING_VERSION = 4.2.1;
MARKETING_VERSION = 4.2.2;
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.sia.DITranquillity-tvOS";
PRODUCT_MODULE_NAME = DITranquillity;
Expand Down Expand Up @@ -1507,7 +1507,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.10;
MARKETING_VERSION = 4.2.1;
MARKETING_VERSION = 4.2.2;
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.sia.DITranquillity-iOS";
PRODUCT_NAME = DITranquillity;
Expand Down Expand Up @@ -1551,7 +1551,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.10;
MARKETING_VERSION = 4.2.1;
MARKETING_VERSION = 4.2.2;
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.sia.DITranquillity-iOS";
PRODUCT_NAME = DITranquillity;
Expand Down Expand Up @@ -1594,7 +1594,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.10;
MARKETING_VERSION = 4.2.1;
MARKETING_VERSION = 4.2.2;
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.sia.DITranquillity-WatchOS";
PRODUCT_MODULE_NAME = DITranquillity;
Expand Down Expand Up @@ -1640,7 +1640,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.10;
MARKETING_VERSION = 4.2.1;
MARKETING_VERSION = 4.2.2;
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = "com.sia.DITranquillity-WatchOS";
PRODUCT_MODULE_NAME = DITranquillity;
Expand Down
4 changes: 2 additions & 2 deletions Sources/Core/API/DIScope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class DIScope {
return
}

let weakStorage = DICacheStorage()
let weakStorage = DIUnsafeCacheStorage()
for (key, value) in storage.any {
weakStorage.save(object: WeakAny(value: value), by: key)
}
Expand All @@ -52,7 +52,7 @@ public class DIScope {
}

internal func toStrongCopy() -> DIScope {
let strongStorage = DICacheStorage()
let strongStorage = DIUnsafeCacheStorage()
for (key, value) in storage.any {
if let weakRef = value as? WeakAny {
if let value = weakRef.value {
Expand Down
34 changes: 32 additions & 2 deletions Sources/Core/API/DIStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,31 +30,39 @@ public protocol DIStorage {
}


/// Contains objects in dictionary by keys
/// Contains objects in dictionary by keys.
public class DICacheStorage: DIStorage {
public var any: [DIComponentInfo: Any] {
lock.lock()
defer { lock.unlock() }
return cache
}

private var cache: [DIComponentInfo: Any] = [:]
private var lock = makeFastLock()

public init() {
}

public func fetch(key: DIComponentInfo) -> Any? {
lock.lock()
defer { lock.unlock() }
return cache[key]
}

public func save(object: Any, by key: DIComponentInfo) {
lock.lock()
defer { lock.unlock() }
cache[key] = object
}

public func clean() {
lock.lock()
defer { lock.unlock() }
cache.removeAll()
}
}


/// Unite few storages for fetch from first containing and save to all.
public class DICompositeStorage: DIStorage {
public var any: [DIComponentInfo: Any] {
Expand Down Expand Up @@ -101,3 +109,25 @@ public class DICompositeStorage: DIStorage {
storages.forEach { $0.clean() }
}
}


/// Contains objects in dictionary by keys
class DIUnsafeCacheStorage: DIStorage {
var any: [DIComponentInfo: Any] {
return cache
}

private var cache: [DIComponentInfo: Any] = [:]

func fetch(key: DIComponentInfo) -> Any? {
return cache[key]
}

func save(object: Any, by key: DIComponentInfo) {
cache[key] = object
}

func clean() {
cache.removeAll()
}
}
2 changes: 1 addition & 1 deletion Sources/Core/API/Hierarchy/DIFramework.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/// Slight expansion over part.
/// Allows you to express more expressively the entry point to the framework of you application.
/// It isn't necessary to create several such classses on one framework - it willn't be convenient.
public protocol DIFramework: class {
public protocol DIFramework: AnyObject {
/// Method inside of which you can registration a components.
/// It's worth combining the components for some reason.
/// And call a class implementing the protocol according to this characteristics.
Expand Down
2 changes: 1 addition & 1 deletion Sources/Core/API/Hierarchy/DIPart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/// Class to maintain code hierarchy.
/// It's necessary for it to be convenient to combine some parts of the system into one common class,
/// and in future to include the part, rather than some list components.
public protocol DIPart: class {
public protocol DIPart: AnyObject {
/// Method inside of which you can registration a components.
/// It's worth combining the components for some reason.
/// And call a class implementing the protocol according to this characteristics.
Expand Down
10 changes: 5 additions & 5 deletions Sources/Core/Internal/Resolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class Resolver {
func resolveCached(component: Component) {
log(.verbose, msg: "Begin resolve cached object by component: \(component.info)", brace: .begin)
defer { log(.verbose, msg: "End resolve cached object by component: \(component.info)", brace: .end) }
_ = makeObject(by: component, use: nil)

mutex.sync { _ = makeObject(by: component, use: nil) }
}

func resolve<T>(type: T.Type = T.self, component: Component) -> T {
Expand Down Expand Up @@ -402,8 +402,8 @@ class Resolver {
private var stack: ContiguousArray<Component.UniqueKey> = []

private class Cache {
fileprivate static let singleStorage = DICacheStorage()
fileprivate let containerStorage = DICacheStorage()
fileprivate static let singleStorage = DIUnsafeCacheStorage()
fileprivate let containerStorage = DIUnsafeCacheStorage()

fileprivate static var single = DIScope(name: "single", storage: singleStorage, policy: .strong)
fileprivate static var weakPerRun = DIScope(name: "per run", storage: singleStorage, policy: .weak)
Expand All @@ -413,7 +413,7 @@ class Resolver {
fileprivate var graph = makeGraphScope()

fileprivate static func makeGraphScope() -> DIScope {
return DIScope(name: "object graph", storage: DICacheStorage(), policy: .strong)
return DIScope(name: "object graph", storage: DIUnsafeCacheStorage(), policy: .strong)
}

fileprivate var cycleInjectionQueue: ContiguousArray<(obj: Any?, signature: MethodSignature)> = []
Expand Down
5 changes: 3 additions & 2 deletions Sources/Core/Internal/threads/Multithread.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ final class PThreadMutex {
func sync<R>(execute: () -> R) -> R {
if DISetting.Defaults.multiThread {
pthread_mutex_lock(&unsafeMutex)
defer { pthread_mutex_unlock(&unsafeMutex) }
return execute()
let result = execute()
pthread_mutex_unlock(&unsafeMutex)
return result
} else {
return execute()
}
Expand Down

0 comments on commit 6e7189e

Please sign in to comment.