Skip to content

Commit

Permalink
auto-injection keys encapsulated in definition
Browse files Browse the repository at this point in the history
  • Loading branch information
Ilya Puchka committed Nov 25, 2015
1 parent 1377a9b commit 75bbfd3
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 52 deletions.
35 changes: 15 additions & 20 deletions Dip/Dip/AutoInjection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,36 +157,31 @@ extension DependencyContainer {

//MARK: - Private

typealias InjectedFactory = ()->Any
typealias InjectedWeakFactory = ()->AnyObject

extension DependencyContainer {
typealias InjectedFactory = ()->Any
typealias InjectedWeakFactory = ()->AnyObject

static func injectedKey<T>(type: T.Type) -> DefinitionKey {
return DefinitionKey(protocolType: Any.self, factoryType: InjectedFactory.self, associatedTag: Injected<T>.tag)
}

static func injectedWeakKey<T>(type: T.Type) -> DefinitionKey {
return DefinitionKey(protocolType: AnyObject.self, factoryType: InjectedWeakFactory.self, associatedTag: InjectedWeak<T>.tag)
}

func registerInjected<T, F>(definition: DefinitionOf<T, F>) {
guard let definition = definition.injectedDefinition else { return }
definitions[DependencyContainer.injectedKey(T.self)] = definition
func registerInjected(definition: Definition) {
guard let key = definition.injectedKey,
definition = definition.injectedDefinition else { return }
definitions[key] = definition
}

func registerInjectedWeak<T, F>(definition: DefinitionOf<T, F>) {
guard let definition = definition.injectedWeakDefinition else { return }
definitions[DependencyContainer.injectedWeakKey(T.self)] = definition
func registerInjectedWeak(definition: Definition) {
guard let key = definition.injectedWeakKey,
definition = definition.injectedWeakDefinition else { return }
definitions[key] = definition
}

func removeInjected<T, F>(definition: DefinitionOf<T, F>) {
func removeInjected(definition: Definition) {
guard definition.injectedDefinition != nil else { return }
definitions[DependencyContainer.injectedKey(T.self)] = nil
definitions[definition.injectedKey] = nil
}

func removeInjectedWeak<T, F>(definition: DefinitionOf<T, F>) {
func removeInjectedWeak(definition: Definition) {
guard definition.injectedWeakDefinition != nil else { return }
definitions[DependencyContainer.injectedWeakKey(T.self)] = nil
definitions[definition.injectedWeakKey] = nil
}

}
Expand Down
46 changes: 33 additions & 13 deletions Dip/Dip/Definition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ struct DefinitionKey : Hashable, Equatable, CustomDebugStringConvertible {
var factoryType: Any.Type
var associatedTag: DependencyContainer.Tag?

init(protocolType: Any.Type, factoryType: Any.Type, associatedTag: DependencyContainer.Tag? = nil) {
self.protocolType = protocolType
self.factoryType = factoryType
self.associatedTag = associatedTag
}

var hashValue: Int {
return "\(protocolType)-\(factoryType)-\(associatedTag)".hashValue
}
Expand Down Expand Up @@ -94,27 +100,33 @@ public final class DefinitionOf<T, F>: Definition {
return self
}

let factory: F
var scope: ComponentScope
var resolveDependenciesBlock: ((DependencyContainer, T) -> ())?
let tag: DependencyContainer.Tag?
private(set) var factory: F
private(set) var scope: ComponentScope = .Prototype

init(factory: F, scope: ComponentScope, tag: DependencyContainer.Tag?) {
private(set) var resolveDependenciesBlock: ((DependencyContainer, T) -> ())?

private init(factory: F) {
self.factory = factory
}

public convenience init(scope: ComponentScope, factory: F) {
self.init(factory: factory)
self.scope = scope
self.tag = tag

if let factory = factory as? ()->T where tag == nil {
injectedDefinition = DefinitionOf<Any, ()->Any>(factory: { factory() }, scope: scope, tag: Injected<T>.tag)
if let factory = factory as? ()->T {
injectedDefinition = DefinitionOf<Any, ()->Any>(factory: { factory() })
injectedDefinition!.scope = scope
injectedKey = DefinitionKey(protocolType: Any.self, factoryType: InjectedFactory.self, associatedTag: Injected<T>.tag)

injectedWeakDefinition = DefinitionOf<AnyObject, ()->AnyObject>(factory: {
guard let result = factory() as? AnyObject else {
fatalError("\(T.self) can not be casted to AnyObject. InjectedWeak wrapper should be used to wrap only classes.")
}
return result
}, scope: scope, tag: InjectedWeak<T>.tag)
})
injectedWeakDefinition!.scope = scope
injectedWeakKey = DefinitionKey(protocolType: AnyObject.self, factoryType: InjectedWeakFactory.self, associatedTag: InjectedWeak<T>.tag)
}

}

///Will be stored only if scope is `Singleton`
Expand All @@ -138,12 +150,20 @@ public final class DefinitionOf<T, F>: Definition {
private var _resolvedInstance: T?

///Accessory definition used to auto-inject strong properties
var injectedDefinition: DefinitionOf<Any,()->Any>?
private(set) var injectedDefinition: DefinitionOf<Any,()->Any>?
private(set) var injectedKey: DefinitionKey?

///Accessory definition used to auto-inject weak properties
var injectedWeakDefinition: DefinitionOf<AnyObject,()->AnyObject>?
private(set) var injectedWeakDefinition: DefinitionOf<AnyObject,()->AnyObject>?
private(set) var injectedWeakKey: DefinitionKey?

}

///Dummy protocol to store definitions for different types in collection
protocol Definition {}
protocol Definition: class {
var injectedDefinition: DefinitionOf<Any,()->Any>? { get }
var injectedKey: DefinitionKey? { get }

var injectedWeakDefinition: DefinitionOf<AnyObject,()->AnyObject>? { get }
var injectedWeakKey: DefinitionKey? { get }
}
37 changes: 18 additions & 19 deletions Dip/Dip/Dip.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ public class DependencyContainer {
- parameter tag: tag used to register definition
- parameter definition: definition to remove
*/
public func remove<T, F>(definition: DefinitionOf<T, F>) {
let key = DefinitionKey(protocolType: T.self, factoryType: F.self, associatedTag: definition.tag)
public func remove<T, F>(definition: DefinitionOf<T, F>, forTag tag: Tag? = nil) {
let key = DefinitionKey(protocolType: T.self, factoryType: F.self, associatedTag: tag)
definitions[key] = nil
removeInjected(definition)
removeInjectedWeak(definition)
Expand Down Expand Up @@ -145,13 +145,8 @@ public class DependencyContainer {
*/
public func registerFactory<T, F>(tag tag: Tag? = nil, scope: ComponentScope, factory: F) -> DefinitionOf<T, F> {
let key = DefinitionKey(protocolType: T.self, factoryType: F.self, associatedTag: tag)
let definition = DefinitionOf<T, F>(factory: factory, scope: scope, tag: tag)
definitions[key] = definition

registerInjected(definition)
registerInjectedWeak(definition)

let definition = DefinitionOf<T, F>(scope: scope, factory: factory)
register(definition, forTag: tag)
return definition
}

Expand All @@ -162,12 +157,14 @@ public class DependencyContainer {
- parameter tag: The arbitrary tag to associate definition with
- parameter definition: definition to register in container
*/
public func register<T, F>(definition: DefinitionOf<T, F>) {
let key = DefinitionKey(protocolType: T.self, factoryType: F.self, associatedTag: definition.tag)
public func register<T, F>(definition: DefinitionOf<T, F>, forTag tag: Tag? = nil) {
let key = DefinitionKey(protocolType: T.self, factoryType: F.self, associatedTag: tag)
definitions[key] = definition

registerInjected(definition)
registerInjectedWeak(definition)
if tag == nil {
registerInjected(definition)
registerInjectedWeak(definition)
}
}

// MARK: Resolve dependencies
Expand Down Expand Up @@ -231,7 +228,7 @@ public class DependencyContainer {
return resolvedInstances.resolve {

if let previouslyResolved: T = resolvedInstances.previouslyResolved(key, definition: definition) {
resolvedInstances.storeResolvedInstance(previouslyResolved, forKey: key)
resolvedInstances.storeResolvedInstance(previouslyResolved, forKey: key, definition: definition)
return previouslyResolved
}
else {
Expand All @@ -241,11 +238,11 @@ public class DependencyContainer {
//when it returns instance that we try to resolve here can be already resolved
//so we return it, throwing away instance created by previous call to builder
if let previouslyResolved: T = resolvedInstances.previouslyResolved(key, definition: definition) {
resolvedInstances.storeResolvedInstance(previouslyResolved, forKey: key)
resolvedInstances.storeResolvedInstance(previouslyResolved, forKey: key, definition: definition)
return previouslyResolved
}

resolvedInstances.storeResolvedInstance(resolvedInstance, forKey: key)
resolvedInstances.storeResolvedInstance(resolvedInstance, forKey: key, definition: definition)
definition.resolvedInstance = resolvedInstance
definition.resolveDependenciesBlock?(self, resolvedInstance)
resolveDependencies(resolvedInstance)
Expand All @@ -265,10 +262,12 @@ public class DependencyContainer {
class ResolvedInstances {
var resolvedInstances = [DefinitionKey: Any]()

func storeResolvedInstance<T>(instance: T, forKey key: DefinitionKey?) {
func storeResolvedInstance<T, F>(instance: T, forKey key: DefinitionKey?, definition: DefinitionOf<T, F>) {
resolvedInstances[key] = instance
resolvedInstances[DependencyContainer.injectedKey(T.self)] = instance
resolvedInstances[DependencyContainer.injectedWeakKey(T.self)] = instance
if key != nil {
resolvedInstances[definition.injectedKey] = instance
resolvedInstances[definition.injectedWeakKey] = instance
}
}

func previouslyResolved<T, F>(key: DefinitionKey?, definition: DefinitionOf<T, F>) -> T? {
Expand Down

0 comments on commit 75bbfd3

Please sign in to comment.