Skip to content

Commit e473eed

Browse files
committed
Streamline critical path through scope caching mechanism
1 parent c35fa86 commit e473eed

File tree

4 files changed

+38
-25
lines changed

4 files changed

+38
-25
lines changed

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Factory Changelog
22

3+
### 1.2.3
4+
5+
* Streamline critical path through scope caching mechanism
6+
37
### 1.2.2
48

59
* Fix issue with optional nil lazy injection

Sources/Factory/Factory.swift

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ open class SharedContainer {
141141
registrations = [:]
142142
}
143143

144-
/// Internal registration function used by Factory
144+
/// Internal registration function used by Factory
145145
fileprivate static func register(id: UUID, factory: AnyFactory) {
146146
defer { lock.unlock() }
147147
lock.lock()
@@ -155,7 +155,7 @@ open class SharedContainer {
155155
return registrations[id]
156156
}
157157

158-
/// Internal reset function used by Factory
158+
/// Internal reset function used by Factory
159159
fileprivate static func reset(_ id: UUID) {
160160
defer { lock.unlock() }
161161
lock.lock()
@@ -197,25 +197,21 @@ open class SharedContainer {
197197
lock.lock()
198198
if let box = cache[id], let instance = box.instance as? T {
199199
if let optional = instance as? OptionalProtocol {
200-
if optional.hasSome {
200+
if optional.hasWrappedValue {
201201
return instance
202202
}
203203
} else {
204204
return instance
205205
}
206206
}
207207
let instance: T = factory()
208-
if let optional = instance as? OptionalProtocol {
209-
if optional.hasSome, let box = box(instance) {
210-
cache[id] = box
211-
}
212-
} else if let box = box(instance) {
208+
if let box = box(instance) {
213209
cache[id] = box
214210
}
215211
return instance
216212
}
217213

218-
/// Internal reset function used by Factory
214+
/// Internal reset function used by Factory
219215
fileprivate func reset(_ id: UUID) {
220216
defer { lock.unlock() }
221217
lock.lock()
@@ -224,7 +220,11 @@ open class SharedContainer {
224220

225221
/// Internal function correctly boxes cache value depending upon scope type
226222
fileprivate func box<T>(_ instance: T) -> AnyBox? {
227-
StrongBox<T>(boxed: instance)
223+
if let optional = instance as? OptionalProtocol {
224+
return optional.hasWrappedValue ? StrongBox<T>(boxed: instance) : nil
225+
} else {
226+
return StrongBox<T>(boxed: instance)
227+
}
228228
}
229229

230230
private var lock = NSLock()
@@ -259,12 +259,10 @@ extension SharedContainer.Scope {
259259
}
260260
fileprivate override func box<T>(_ instance: T) -> AnyBox? {
261261
if let optional = instance as? OptionalProtocol {
262-
// Actual wrapped type could be value, protocol, or something else so we need to check if wrapped instance is class type
263-
if let unwrapped = optional.unwrap(), type(of: unwrapped) is AnyObject.Type {
264-
// box original type so we match type when item retrieved from cache
265-
return WeakBox(boxed: instance as AnyObject)
262+
if let unwrapped = optional.wrappedValue, type(of: unwrapped) is AnyObject.Type {
263+
return WeakBox(boxed: unwrapped as AnyObject)
266264
}
267-
} else if type(of: instance) is AnyClass {
265+
} else if type(of: instance) is AnyObject.Type {
268266
return WeakBox(boxed: instance as AnyObject)
269267
}
270268
return nil
@@ -367,21 +365,29 @@ private struct Registration<P,T> {
367365

368366
/// Internal protocol used to evaluate optional types for caching
369367
private protocol OptionalProtocol {
370-
var hasSome: Bool { get }
371-
func unwrap() -> Any?
368+
var hasWrappedValue: Bool { get }
369+
var wrappedType: Any.Type { get }
370+
var wrappedValue: Any? { get }
372371
}
373372

374373
extension Optional : OptionalProtocol {
375-
fileprivate var hasSome: Bool {
374+
var hasWrappedValue: Bool {
376375
switch self {
377-
case .none: return false
378-
case .some: return true
376+
case .none:
377+
return false
378+
case .some:
379+
return true
379380
}
380381
}
381-
fileprivate func unwrap() -> Any? {
382+
var wrappedType: Any.Type {
383+
Wrapped.self
384+
}
385+
var wrappedValue: Any? {
382386
switch self {
383-
case .none: return nil
384-
case .some(let unwrapped): return unwrapped
387+
case .none:
388+
return nil
389+
case .some(let value):
390+
return value
385391
}
386392
}
387393
}
@@ -395,7 +401,7 @@ private protocol AnyBox {
395401
private struct StrongBox<T>: AnyBox {
396402
let boxed: T
397403
var instance: Any {
398-
boxed
404+
boxed as Any
399405
}
400406
}
401407

Tests/FactoryTests/FactoryDefectTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ final class FactoryDefectTests: XCTestCase {
4848
MyService()
4949
}
5050
XCTAssertNil(service1.service)
51-
}
51+
}
5252

5353
}
5454

Tests/FactoryTests/FactoryScopeTests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ final class FactoryScopeTests: XCTestCase {
5252
service2 = nil
5353
let service3: MyServiceType? = Container.sharedService()
5454
XCTAssertNotNil(service3)
55+
// Shared instance should have released so new and old ids should not match
5556
XCTAssertTrue(service2?.id != service3?.id)
5657
}
5758

@@ -66,6 +67,7 @@ final class FactoryScopeTests: XCTestCase {
6667
service2 = nil
6768
let service3: MyServiceType? = Container.optionalSharedService()
6869
XCTAssertNotNil(service3)
70+
// Shared instance should have released so new and old ids should not match
6971
XCTAssertTrue(service2?.id != service3?.id)
7072
}
7173

@@ -80,6 +82,7 @@ final class FactoryScopeTests: XCTestCase {
8082
service2 = nil
8183
let service3: MyServiceType? = Container.optionalValueService()
8284
XCTAssertNotNil(service3)
85+
// New and old ids should still not match
8386
XCTAssertTrue(service2?.id != service3?.id)
8487
}
8588

0 commit comments

Comments
 (0)