Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cbf63cf044 | |||
| de4cbcc7ed | |||
| d295b6909c | |||
| 56e4250eac | |||
| 15bc776a0a | |||
| 16e68a0e1c | |||
| 61a2bacd73 | |||
| dd3dd2cf9b |
@@ -1,5 +1,12 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 0.0.2
|
||||
|
||||
* Switched from class methods to instance methods ([#1](https://github.com/AliSoftware/Dip/issues/1)). This allows you to have multiple `DependencyContainers`
|
||||
* Renamed the class from `Dependency` to `DependencyContainer`
|
||||
* Renamed the `instanceFactory:` parameter to `factory:`
|
||||
* Made the `DependencyContainer` generic of the type of _tag_. We are no longer limited to tags of type `String`, we can now use anything that's `Equatable`.
|
||||
|
||||
## 0.0.1
|
||||
|
||||
Initial version to release the early proof of concept.
|
||||
|
||||
@@ -10,19 +10,34 @@
|
||||
097D52E81BC13B0D006C893C /* WebServiceAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52E71BC13B0D006C893C /* WebServiceAPI.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D52EA1BC15FFF006C893C /* PersonFactoryAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52E91BC15FFF006C893C /* PersonFactoryAPI.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D52ED1BC16091006C893C /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52EC1BC16091006C893C /* Person.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D52EF1BC1611C006C893C /* StarWarsWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52EE1BC1611C006C893C /* StarWarsWS.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D52EF1BC1611C006C893C /* SWAPIWebService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52EE1BC1611C006C893C /* SWAPIWebService.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D52F11BC161F7006C893C /* SerializerAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F01BC161F7006C893C /* SerializerAPI.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D52F51BC166F3006C893C /* JSONSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F41BC166F3006C893C /* JSONSerializer.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D52F71BC169C0006C893C /* StarWarsPersonFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F61BC169C0006C893C /* StarWarsPersonFactory.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D52F71BC169C0006C893C /* SWAPIPersonFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F61BC169C0006C893C /* SWAPIPersonFactory.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D52F91BC17418006C893C /* PersonFormatterAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F81BC17418006C893C /* PersonFormatterAPI.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D52FB1BC1745B006C893C /* MassHeightFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52FA1BC1745B006C893C /* MassHeightFormatter.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D52FD1BC174B6006C893C /* EyesHairFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52FC1BC174B6006C893C /* EyesHairFormatter.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D53011BC31F4A006C893C /* Tags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D53001BC31F4A006C893C /* Tags.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D53021BC31FA6006C893C /* WebServiceAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52E71BC13B0D006C893C /* WebServiceAPI.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D53031BC31FA6006C893C /* SerializerAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F01BC161F7006C893C /* SerializerAPI.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D53041BC31FA6006C893C /* PersonFactoryAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52E91BC15FFF006C893C /* PersonFactoryAPI.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D53051BC31FA6006C893C /* PersonFormatterAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F81BC17418006C893C /* PersonFormatterAPI.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D53061BC31FAE006C893C /* SWAPIWebService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52EE1BC1611C006C893C /* SWAPIWebService.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D53071BC31FC5006C893C /* Tags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D53001BC31F4A006C893C /* Tags.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D53081BC32053006C893C /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52EC1BC16091006C893C /* Person.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D530A1BC3243D006C893C /* NetworkLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D53091BC3243D006C893C /* NetworkLayer.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D530C1BC324DA006C893C /* NSURLSessionNetworkLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D530B1BC324DA006C893C /* NSURLSessionNetworkLayer.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D530D1BC3250B006C893C /* SWAPIPersonFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F61BC169C0006C893C /* SWAPIPersonFactory.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D530E1BC3250E006C893C /* JSONSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52F41BC166F3006C893C /* JSONSerializer.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D530F1BC3250E006C893C /* MassHeightFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52FA1BC1745B006C893C /* MassHeightFormatter.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D53101BC3250E006C893C /* EyesHairFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D52FC1BC174B6006C893C /* EyesHairFormatter.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
097D53111BC32513006C893C /* NetworkLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097D53091BC3243D006C893C /* NetworkLayer.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
099022621BC123C000E76F43 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099022611BC123C000E76F43 /* AppDelegate.swift */; };
|
||||
099022641BC123C000E76F43 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 099022631BC123C000E76F43 /* ViewController.swift */; };
|
||||
099022671BC123C000E76F43 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 099022651BC123C000E76F43 /* Main.storyboard */; };
|
||||
099022691BC123C000E76F43 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 099022681BC123C000E76F43 /* Assets.xcassets */; };
|
||||
0990226C1BC123C000E76F43 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0990226A1BC123C000E76F43 /* LaunchScreen.storyboard */; };
|
||||
607FACEC1AFB9204008FA782 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* Tests.swift */; };
|
||||
607FACEC1AFB9204008FA782 /* SWAPIWebServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* SWAPIWebServiceTests.swift */; };
|
||||
7BBD849465D99D9D1987AE6D /* Pods_DipTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 304AD039660A2C58EB08D985 /* Pods_DipTests.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
84D8EBE5B2D583BEFB17C45A /* Pods_DipSampleApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FE9C70E965FF88C3F20AC76 /* Pods_DipSampleApp.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
/* End PBXBuildFile section */
|
||||
@@ -31,14 +46,17 @@
|
||||
097D52E71BC13B0D006C893C /* WebServiceAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebServiceAPI.swift; sourceTree = "<group>"; };
|
||||
097D52E91BC15FFF006C893C /* PersonFactoryAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonFactoryAPI.swift; sourceTree = "<group>"; };
|
||||
097D52EC1BC16091006C893C /* Person.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Person.swift; sourceTree = "<group>"; };
|
||||
097D52EE1BC1611C006C893C /* StarWarsWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsWS.swift; sourceTree = "<group>"; };
|
||||
097D52EE1BC1611C006C893C /* SWAPIWebService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWAPIWebService.swift; sourceTree = "<group>"; };
|
||||
097D52F01BC161F7006C893C /* SerializerAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SerializerAPI.swift; sourceTree = "<group>"; };
|
||||
097D52F41BC166F3006C893C /* JSONSerializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONSerializer.swift; sourceTree = "<group>"; };
|
||||
097D52F61BC169C0006C893C /* StarWarsPersonFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsPersonFactory.swift; sourceTree = "<group>"; };
|
||||
097D52F61BC169C0006C893C /* SWAPIPersonFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWAPIPersonFactory.swift; sourceTree = "<group>"; };
|
||||
097D52F81BC17418006C893C /* PersonFormatterAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonFormatterAPI.swift; sourceTree = "<group>"; };
|
||||
097D52FA1BC1745B006C893C /* MassHeightFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MassHeightFormatter.swift; sourceTree = "<group>"; };
|
||||
097D52FC1BC174B6006C893C /* EyesHairFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EyesHairFormatter.swift; sourceTree = "<group>"; };
|
||||
097D52FE1BC18A09006C893C /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = CHANGELOG.md; path = ../CHANGELOG.md; sourceTree = "<group>"; };
|
||||
097D53001BC31F4A006C893C /* Tags.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tags.swift; sourceTree = "<group>"; };
|
||||
097D53091BC3243D006C893C /* NetworkLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkLayer.swift; sourceTree = "<group>"; };
|
||||
097D530B1BC324DA006C893C /* NSURLSessionNetworkLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURLSessionNetworkLayer.swift; sourceTree = "<group>"; };
|
||||
0990225F1BC123C000E76F43 /* DipSampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DipSampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
099022611BC123C000E76F43 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
099022631BC123C000E76F43 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
@@ -50,7 +68,7 @@
|
||||
304AD039660A2C58EB08D985 /* Pods_DipTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DipTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
607FACE51AFB9204008FA782 /* DipTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DipTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
607FACEB1AFB9204008FA782 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = "<group>"; };
|
||||
607FACEB1AFB9204008FA782 /* SWAPIWebServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SWAPIWebServiceTests.swift; sourceTree = "<group>"; };
|
||||
64B6CB26CB93DFD18565BB72 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
|
||||
6AB71DAFECF410F2FB12A44C /* Pods-DipSampleApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DipSampleApp.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DipSampleApp/Pods-DipSampleApp.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
7E5EDFB4A9194B50CAED7E1A /* Pods-DipTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DipTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DipTests/Pods-DipTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -83,7 +101,7 @@
|
||||
097D52E61BC139A8006C893C /* Services */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
097D52F21BC16258006C893C /* APIs */,
|
||||
097D52F21BC16258006C893C /* Protocols */,
|
||||
097D52F31BC16271006C893C /* Implementations */,
|
||||
);
|
||||
path = Services;
|
||||
@@ -97,27 +115,29 @@
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
097D52F21BC16258006C893C /* APIs */ = {
|
||||
097D52F21BC16258006C893C /* Protocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
097D52E71BC13B0D006C893C /* WebServiceAPI.swift */,
|
||||
097D52F01BC161F7006C893C /* SerializerAPI.swift */,
|
||||
097D52E91BC15FFF006C893C /* PersonFactoryAPI.swift */,
|
||||
097D52F81BC17418006C893C /* PersonFormatterAPI.swift */,
|
||||
097D53091BC3243D006C893C /* NetworkLayer.swift */,
|
||||
);
|
||||
name = APIs;
|
||||
path = Protocols;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
097D52F31BC16271006C893C /* Implementations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
097D52EE1BC1611C006C893C /* StarWarsWS.swift */,
|
||||
097D52F61BC169C0006C893C /* StarWarsPersonFactory.swift */,
|
||||
097D52EE1BC1611C006C893C /* SWAPIWebService.swift */,
|
||||
097D52F61BC169C0006C893C /* SWAPIPersonFactory.swift */,
|
||||
097D52F41BC166F3006C893C /* JSONSerializer.swift */,
|
||||
097D52FA1BC1745B006C893C /* MassHeightFormatter.swift */,
|
||||
097D52FC1BC174B6006C893C /* EyesHairFormatter.swift */,
|
||||
097D530B1BC324DA006C893C /* NSURLSessionNetworkLayer.swift */,
|
||||
);
|
||||
name = Implementations;
|
||||
path = Implementations;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
099022601BC123C000E76F43 /* DipSampleApp */ = {
|
||||
@@ -125,6 +145,7 @@
|
||||
children = (
|
||||
097D52EB1BC16083006C893C /* Model */,
|
||||
097D52E61BC139A8006C893C /* Services */,
|
||||
097D53001BC31F4A006C893C /* Tags.swift */,
|
||||
099022611BC123C000E76F43 /* AppDelegate.swift */,
|
||||
099022631BC123C000E76F43 /* ViewController.swift */,
|
||||
099022651BC123C000E76F43 /* Main.storyboard */,
|
||||
@@ -168,7 +189,7 @@
|
||||
607FACE81AFB9204008FA782 /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
607FACEB1AFB9204008FA782 /* Tests.swift */,
|
||||
607FACEB1AFB9204008FA782 /* SWAPIWebServiceTests.swift */,
|
||||
607FACE91AFB9204008FA782 /* Supporting Files */,
|
||||
);
|
||||
path = Tests;
|
||||
@@ -402,14 +423,17 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
097D530A1BC3243D006C893C /* NetworkLayer.swift in Sources */,
|
||||
097D52ED1BC16091006C893C /* Person.swift in Sources */,
|
||||
097D52F11BC161F7006C893C /* SerializerAPI.swift in Sources */,
|
||||
097D52F91BC17418006C893C /* PersonFormatterAPI.swift in Sources */,
|
||||
099022641BC123C000E76F43 /* ViewController.swift in Sources */,
|
||||
097D530C1BC324DA006C893C /* NSURLSessionNetworkLayer.swift in Sources */,
|
||||
097D52F51BC166F3006C893C /* JSONSerializer.swift in Sources */,
|
||||
097D53011BC31F4A006C893C /* Tags.swift in Sources */,
|
||||
099022621BC123C000E76F43 /* AppDelegate.swift in Sources */,
|
||||
097D52F71BC169C0006C893C /* StarWarsPersonFactory.swift in Sources */,
|
||||
097D52EF1BC1611C006C893C /* StarWarsWS.swift in Sources */,
|
||||
097D52F71BC169C0006C893C /* SWAPIPersonFactory.swift in Sources */,
|
||||
097D52EF1BC1611C006C893C /* SWAPIWebService.swift in Sources */,
|
||||
097D52FD1BC174B6006C893C /* EyesHairFormatter.swift in Sources */,
|
||||
097D52FB1BC1745B006C893C /* MassHeightFormatter.swift in Sources */,
|
||||
097D52E81BC13B0D006C893C /* WebServiceAPI.swift in Sources */,
|
||||
@@ -421,7 +445,19 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
607FACEC1AFB9204008FA782 /* Tests.swift in Sources */,
|
||||
607FACEC1AFB9204008FA782 /* SWAPIWebServiceTests.swift in Sources */,
|
||||
097D53051BC31FA6006C893C /* PersonFormatterAPI.swift in Sources */,
|
||||
097D53071BC31FC5006C893C /* Tags.swift in Sources */,
|
||||
097D53111BC32513006C893C /* NetworkLayer.swift in Sources */,
|
||||
097D53021BC31FA6006C893C /* WebServiceAPI.swift in Sources */,
|
||||
097D53041BC31FA6006C893C /* PersonFactoryAPI.swift in Sources */,
|
||||
097D530E1BC3250E006C893C /* JSONSerializer.swift in Sources */,
|
||||
097D53031BC31FA6006C893C /* SerializerAPI.swift in Sources */,
|
||||
097D53081BC32053006C893C /* Person.swift in Sources */,
|
||||
097D53101BC3250E006C893C /* EyesHairFormatter.swift in Sources */,
|
||||
097D530F1BC3250E006C893C /* MassHeightFormatter.swift in Sources */,
|
||||
097D530D1BC3250B006C893C /* SWAPIPersonFactory.swift in Sources */,
|
||||
097D53061BC31FAE006C893C /* SWAPIWebService.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -9,18 +9,16 @@
|
||||
import UIKit
|
||||
import Dip
|
||||
|
||||
enum PersonFormatterTags : String {
|
||||
case MassHeight
|
||||
case EyesHair
|
||||
}
|
||||
|
||||
private let _dependencies: Void = {
|
||||
Dependency.register(instance: StarWarsWebService() as WebServiceAPI)
|
||||
Dependency.register(instance: StarWarsJSONPersonFactory() as PersonFactoryAPI)
|
||||
Dependency.register(instance: JSONSerializer() as SerializerAPI)
|
||||
Dependency.register(PersonFormatterTags.MassHeight.rawValue, instance: MassHeightFormatter() as PersonFormatterAPI)
|
||||
Dependency.register(PersonFormatterTags.EyesHair.rawValue, instance: EyesHairFormatter() as PersonFormatterAPI)
|
||||
}()
|
||||
let dip: DependencyContainer<PersonFormatterTag> = {
|
||||
let dip = DependencyContainer<PersonFormatterTag>()
|
||||
dip.register(instance: NSURLSessionNetworkLayer() as NetworkLayer)
|
||||
dip.register(instance: SWAPIWebService() as WebServiceAPI)
|
||||
dip.register(instance: SWAPIPersonFactory() as PersonFactoryAPI)
|
||||
dip.register(instance: JSONSerializer() as SerializerAPI)
|
||||
dip.register(.MassHeight, instance: MassHeightFormatter() as PersonFormatterAPI)
|
||||
dip.register(.EyesHair, instance: EyesHairFormatter() as PersonFormatterAPI)
|
||||
return dip
|
||||
}()
|
||||
|
||||
|
||||
@UIApplicationMain
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// NSURLSessionNetworkLayer.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 05/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class NSURLSessionNetworkLayer : NetworkLayer {
|
||||
let session = NSURLSession.sharedSession()
|
||||
|
||||
func fetchURL(url: NSURL, completion: NSData? -> Void) {
|
||||
let task = session.dataTaskWithURL(url) { (data: NSData?, resp: NSURLResponse?, error: NSError?) -> Void in
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
completion(data)
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// StarWarsJSONPersonFactory.swift
|
||||
// SWAPIPersonFactory.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 04/10/2015.
|
||||
@@ -9,16 +9,16 @@
|
||||
import Foundation
|
||||
import Dip
|
||||
|
||||
class StarWarsJSONPersonFactory : PersonFactoryAPI {
|
||||
class SWAPIPersonFactory : PersonFactoryAPI {
|
||||
typealias JSONDict = [String:AnyObject]
|
||||
enum Error : ErrorType {
|
||||
case MissingResultsEntry
|
||||
case InvalidPersonSchema
|
||||
}
|
||||
|
||||
let serializer = Dependency.resolve() as SerializerAPI
|
||||
let serializer = dip.resolve() as SerializerAPI
|
||||
|
||||
func personListFromData(personData: NSData) throws -> [Person] {
|
||||
func peopleFromData(personData: NSData) throws -> [Person] {
|
||||
let json = try serializer.dictionaryFromData(personData)
|
||||
if let results = json["results"] as? [JSONDict] {
|
||||
return try results.map { try personFromJSON($0) }
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// SWAPIWebService.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 04/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Dip
|
||||
|
||||
/// WebService for The StarWars API — see http://swapi.co/documentation
|
||||
class SWAPIWebService : WebServiceAPI {
|
||||
let networkLayer = dip.resolve() as NetworkLayer
|
||||
let personFactory = dip.resolve() as PersonFactoryAPI
|
||||
|
||||
func fetch(completion: [Person]? -> Void) {
|
||||
let url = NSURL(string: "http://swapi.co/api/people/")!
|
||||
networkLayer.fetchURLAndMap(url, completion: completion) { data in
|
||||
return try self.personFactory.peopleFromData(data)
|
||||
}
|
||||
}
|
||||
|
||||
func fetch(id: Int, completion: Person? -> Void) {
|
||||
let url = NSURL(string: "http://swapi.co/api/people/\(id)")!
|
||||
networkLayer.fetchURLAndMap(url, completion: completion) { data in
|
||||
return try self.personFactory.personFromData(data)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// NetworkLayer.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 05/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol NetworkLayer {
|
||||
func fetchURL(url: NSURL, completion: NSData? -> Void)
|
||||
func fetchURLAndMap<T>(url: NSURL, completion: T? -> Void, transform: NSData throws -> T)
|
||||
}
|
||||
|
||||
extension NetworkLayer {
|
||||
func fetchURLAndMap<T>(url: NSURL, completion: T? -> Void, transform: NSData throws -> T) {
|
||||
fetchURL(url) { (data: NSData?) -> Void in
|
||||
guard let data = data else {
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
let result: T?
|
||||
do {
|
||||
result = try transform(data)
|
||||
} catch {
|
||||
result = nil
|
||||
}
|
||||
completion(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -9,6 +9,6 @@
|
||||
import Foundation
|
||||
|
||||
protocol PersonFactoryAPI {
|
||||
func personListFromData(personData: NSData) throws -> [Person]
|
||||
func peopleFromData(personData: NSData) throws -> [Person]
|
||||
func personFromData(personData: NSData) throws -> Person
|
||||
}
|
||||
+2
-2
@@ -9,6 +9,6 @@
|
||||
import Foundation
|
||||
|
||||
protocol WebServiceAPI {
|
||||
func fetchPeopleList(completion: [Person]? -> Void)
|
||||
func fetchPerson(id: Int, completion: Person? -> Void)
|
||||
func fetch(completion: [Person]? -> Void)
|
||||
func fetch(id: Int, completion: Person? -> Void)
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
//
|
||||
// StarWarsWebService.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 04/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Dip
|
||||
|
||||
class StarWarsWebService : WebServiceAPI {
|
||||
let personFactory = Dependency.resolve() as PersonFactoryAPI
|
||||
|
||||
func fetchPeopleList(completion: [Person]? -> Void) {
|
||||
let url = NSURL(string: "http://swapi.co/api/people/")!
|
||||
fetchURL(url) { data in
|
||||
guard let data = data else { completion(nil); return }
|
||||
let persons: [Person]?
|
||||
do {
|
||||
persons = try self.personFactory.personListFromData(data)
|
||||
} catch {
|
||||
persons = nil
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
completion(persons)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fetchPerson(id: Int, completion: Person? -> Void) {
|
||||
let url = NSURL(string: "http://swapi.co/api/people/\(id)")!
|
||||
fetchURL(url) { data in
|
||||
guard let data = data else { completion(nil); return }
|
||||
let person: Person?
|
||||
do {
|
||||
person = try self.personFactory.personFromData(data)
|
||||
} catch {
|
||||
person = nil
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
completion(person)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchURL(url: NSURL, completion: NSData? -> Void) {
|
||||
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data: NSData?, resp: NSURLResponse?, error: NSError?) -> Void in
|
||||
completion(data)
|
||||
}
|
||||
task.resume()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Tags.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 05/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum PersonFormatterTag {
|
||||
case MassHeight
|
||||
case EyesHair
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import Dip
|
||||
let kCellIdentifier = "Cell"
|
||||
|
||||
class ViewController: UIViewController {
|
||||
let ws = Dependency.resolve() as WebServiceAPI
|
||||
let ws = dip.resolve() as WebServiceAPI
|
||||
|
||||
var personList = [Person]()
|
||||
|
||||
@@ -23,7 +23,7 @@ class ViewController: UIViewController {
|
||||
@IBAction func fetchPeople(sender: UIButton) {
|
||||
sender.enabled = false
|
||||
self.activityIndicator.startAnimating()
|
||||
ws.fetchPeopleList { persons in
|
||||
ws.fetch { persons in
|
||||
self.activityIndicator.stopAnimating()
|
||||
sender.enabled = true
|
||||
self.personList = persons ?? []
|
||||
@@ -46,17 +46,19 @@ extension ViewController : UITableViewDataSource {
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier, forIndexPath: indexPath)
|
||||
|
||||
let person = personList[indexPath.row]
|
||||
let formatter = Dependency.resolve(formatterTag) as PersonFormatterAPI
|
||||
let formatter = dip.resolve(formatterTag) as PersonFormatterAPI
|
||||
cell.textLabel?.text = formatter.textForPerson(person)
|
||||
cell.detailTextLabel?.text = formatter.subtextForPerson(person)
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
var formatterTag: String {
|
||||
var formatterTag: PersonFormatterTag {
|
||||
switch displayModeSelector.selectedSegmentIndex {
|
||||
case 0: return PersonFormatterTags.MassHeight.rawValue
|
||||
default: return PersonFormatterTags.EyesHair.rawValue
|
||||
case 0:
|
||||
return .MassHeight
|
||||
default:
|
||||
return .EyesHair
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import UIKit
|
||||
import XCTest
|
||||
import Dip
|
||||
|
||||
|
||||
var dip = DependencyContainer<PersonFormatterTag>()
|
||||
|
||||
let p1 = ["name": "John Doe", "mass": "72", "height": "172", "eye_color": "brown", "hair_color": "black"]
|
||||
let p2 = ["name": "Jane Doe", "mass": "63", "height": "167", "eye_color": "blue", "hair_color": "red"]
|
||||
|
||||
class SWAPIWebServiceTests: XCTestCase {
|
||||
|
||||
// MARK: - Mock object used for tests
|
||||
|
||||
struct NetworkMock : NetworkLayer {
|
||||
let fakeData: NSData?
|
||||
|
||||
init(json: AnyObject) {
|
||||
do {
|
||||
fakeData = try NSJSONSerialization.dataWithJSONObject(json, options: [])
|
||||
} catch {
|
||||
fakeData = nil
|
||||
}
|
||||
}
|
||||
|
||||
func fetchURL(url: NSURL, completion: NSData? -> Void) {
|
||||
completion(fakeData)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Test Suite
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
dip.reset()
|
||||
dip.register(instance: SWAPIPersonFactory() as PersonFactoryAPI)
|
||||
dip.register(instance: JSONSerializer() as SerializerAPI)
|
||||
}
|
||||
|
||||
func testFetchPersons() {
|
||||
let mock = NetworkMock(json: ["results":[p1,p2]])
|
||||
dip.register(instance: mock as NetworkLayer)
|
||||
|
||||
let ws = SWAPIWebService()
|
||||
ws.fetch { persons in
|
||||
XCTAssertNotNil(persons)
|
||||
XCTAssertEqual(persons?.count, 2)
|
||||
|
||||
XCTAssertEqual(persons?[0].name, "John Doe")
|
||||
XCTAssertEqual(persons?[0].mass, 72)
|
||||
XCTAssertEqual(persons?[0].height, 172)
|
||||
XCTAssertEqual(persons?[0].eyesColor, "brown")
|
||||
XCTAssertEqual(persons?[0].hairColor, "black")
|
||||
|
||||
XCTAssertEqual(persons?[1].name, "Jane Doe")
|
||||
XCTAssertEqual(persons?[1].mass, 63)
|
||||
XCTAssertEqual(persons?[1].height, 167)
|
||||
XCTAssertEqual(persons?[1].eyesColor, "blue")
|
||||
XCTAssertEqual(persons?[1].hairColor, "red")
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchOnePerson() {
|
||||
let mock = NetworkMock(json: p1)
|
||||
dip.register(instance: mock as NetworkLayer)
|
||||
|
||||
let ws = SWAPIWebService()
|
||||
ws.fetch(1) { person in
|
||||
XCTAssertNotNil(person)
|
||||
XCTAssertEqual(person?.name, "John Doe")
|
||||
XCTAssertEqual(person?.mass, 72)
|
||||
XCTAssertEqual(person?.height, 172)
|
||||
XCTAssertEqual(person?.eyesColor, "brown")
|
||||
XCTAssertEqual(person?.hairColor, "black")
|
||||
}
|
||||
}
|
||||
|
||||
func testFetchInvalidPerson() {
|
||||
let json = ["error":"whoops"]
|
||||
let mock = NetworkMock(json: json)
|
||||
dip.register(instance: mock as NetworkLayer)
|
||||
|
||||
let ws = SWAPIWebService()
|
||||
ws.fetch(12) { person in
|
||||
XCTAssertNil(person)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import UIKit
|
||||
import XCTest
|
||||
import Dip
|
||||
|
||||
class Tests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testExample() {
|
||||
// This is an example of a functional test case.
|
||||
XCTAssert(true, "Pass")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,13 +13,12 @@ _Photo by [Matthew Hine](http://www.flickr.com/photos/75771631@N00), cc-by-2.0_
|
||||
`Dip` is a simple **Dependency Injection Container**.
|
||||
|
||||
It's not true Dependency Injection, but it's damn close, and aimed to be as simple as possible.
|
||||
It's inspired by `C#`'s [Unity Container](https://msdn.microsoft.com/library/ff647202.aspx).
|
||||
It's inspired by `.NET`'s [Unity Container](https://msdn.microsoft.com/library/ff647202.aspx).
|
||||
|
||||
* You start by **registering all your dependencies, by associating a `protocol` to an `instance` or to an `instanceFactory`**. So for example you'll register an association between the `protocol WebServiceAPI` and an instance or type of `MyRealWebService`.
|
||||
* Then anywhere in your application, you can call `Dependency.resolve()` to **resolve a `protocol` into an instance of a concrete type**.
|
||||
* You start by creating `let dc = DependencyContainer()` and **register all your dependencies, by associating a `protocol` to an `instance` or a `factory`**.
|
||||
* Then anywhere in your application, you can call `dc.resolve()` to **resolve a `protocol` into an instance of a concrete type** using that `DependencyContainer`.
|
||||
|
||||
This allows you to define the real, concrete types only in one place (typically in your `AppDelegate` for your app, in your `setup` for your Unit Tests)
|
||||
and **then only work with `protocols` in your code** (which only define an API contract), without worrying about the real implementation.
|
||||
This allows you to define the real, concrete types only in one place ([typically at the top of your `AppDelegate` for your app](https://github.com/AliSoftware/Dip/blob/master/Example/DipSampleApp/AppDelegate.swift#L12-L21), and [in your `setUp` for your Unit Tests](https://github.com/AliSoftware/Dip/blob/master/Example/Tests/SWAPIWebServiceTests.swift#L36-L38)) and then [only work with `protocols` in your code](https://github.com/AliSoftware/Dip/blob/master/Example/DipSampleApp/ViewController.swift#L15) (which only define an API contract), without worrying about the real implementation.
|
||||
|
||||
## Advantages of DI and loose coupling
|
||||
|
||||
@@ -41,61 +40,62 @@ pod "Dip"
|
||||
|
||||
### Register instances and instance factories
|
||||
|
||||
At the beginning of your app's life-cycle, you register instances and instance factories with protocols.
|
||||
First, create a `DependencyContainer` and use it to register instances and factories with protocols, using those methods:
|
||||
|
||||
* `register(instance: _)` will register a singleton instance with a given protocol.
|
||||
* `register(instanceFactory: _)` will register an instance factory — which generates a new instance each time you `resolve()`.
|
||||
* You need _cast the instance to the protocol type_ you want to register it with (e.g. `register(instance: PlistUsersProvider() as UsersListProviderType)`).
|
||||
* if you give a `tag` in the parameter to `register()`, it will associate that instance or instance factory with this tag, which can be used later during `resolve` (see below).
|
||||
* `register(factory: _)` will register an instance factory — which generates a new instance each time you `resolve()`.
|
||||
* You need **cast the instance to the protocol type** you want to register it with (e.g. `register(instance: PlistUsersProvider() as UsersListProviderType)`).
|
||||
|
||||
Typically, to register your dependencies as early as possible in your app life-cycle, you can do that either:
|
||||
|
||||
* in `@objc class func initialize() {}` declared in an `extension Dependency`, so it's called automatically before the first call to `Dependency.resolve()`
|
||||
* or using a `private let _dependencies: Void = { … }()` (for example at the top of your `AppDelegate.swift`) as a trick to have code called as soon as the app in loaded
|
||||
* In your (non-hosted, standalone) unit tests, you'll probably declare them in your `func setup()` for example
|
||||
Typically, to register your dependencies as early as possible in your app life-cycle, you will declare a `let dip: DependencyContainer = { … }()` somewhere (for example [at the top of your `AppDelegate.swift`](https://github.com/AliSoftware/Dip/blob/master/Example/DipSampleApp/AppDelegate.swift#L12-L21)).
|
||||
In your (non-hosted, standalone) unit tests, you'll probably [declare them in your `func setUp()`](https://github.com/AliSoftware/Dip/blob/master/Example/Tests/SWAPIWebServiceTests.swift#L36-L38) instead.
|
||||
|
||||
### Resolve dependencies
|
||||
|
||||
* `Dependency.resolve()` will return a new instance matching the requested protocol.
|
||||
* `resolve()` will return a new instance matching the requested protocol.
|
||||
* Explicitly specify the return type of `resolve` so that Swift's type inference knows which protocol you're trying to resolve.
|
||||
* If that protocol was registered as a singleton instance (using `register(instance: …)`, the same instance will be returned each time you call `resolve()` for this protocol type. Otherwise, the instance factory will generate a new instance each time.
|
||||
* `Dependency.resolve(tag)` will try to find an instance (or instance factory) that match both the requested protocol _and_ the tag. If it doesn't find any, it will fallback to an instance (or instance factory) that only match the requested protocol.
|
||||
|
||||
### Using tags to associate various factories to one protocol
|
||||
|
||||
* If you give a `tag` in the parameter to `register()`, it will associate that instance or factory with this tag, which can be used later during `resolve` (see below).
|
||||
* `resolve(tag)` will try to find an instance (or instance factory) that match both the requested protocol _and_ the tag. If it doesn't find any, it will fallback to an instance (or instance factory) that only match the requested protocol.
|
||||
* The tags can be anything, as long as it's of a type conforming to `Equatable`. `DependencyContainer` is a generic class which takes that type as generic parameter (so one `DependencyContainer` will be tied with a given tag type)
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
Somewhere in your App target, register the dependencies. Best place to do that is probably in `Dependency.initialize()`:
|
||||
Somewhere in your App target, register the dependencies:
|
||||
|
||||
```swift
|
||||
extension Dependency {
|
||||
@objc class func initialize() {
|
||||
let env = ProductionEnvironment(analytics: true)
|
||||
Dependency.register(instance: env as EnvironmentType)
|
||||
Dependency.register(instance: WebService() as WebServiceType)
|
||||
Dependency.register() { DummyFriendsProvider(user: $0 ?? "Jane Doe") as FriendsProviderType }
|
||||
Dependency.register("me") { PlistFriendsProvider(plist: "myfriends") as FriendsProviderType }
|
||||
}
|
||||
let dip: DependencyContainer<String> = {
|
||||
let dip = DependencyContainer<String>()
|
||||
let env = ProductionEnvironment(analytics: true)
|
||||
dip.register(instance: env as EnvironmentType)
|
||||
dip.register(instance: WebService() as WebServiceType)
|
||||
dip.register() { DummyFriendsProvider(user: $0 ?? "Jane Doe") as FriendsProviderType }
|
||||
dip.register("me") { PlistFriendsProvider(plist: "myfriends") as FriendsProviderType }
|
||||
return dip
|
||||
}
|
||||
```
|
||||
|
||||
> Do the same in your Unit Tests target & test cases, but obviously with different Dependencies registered, depending on what you want to test and what instances you need to inject to provide dummy implementations for your tests.
|
||||
|
||||
|
||||
Then to use dependencies throughout your app, use `Dependency.resolve()`, like this:
|
||||
Then to use dependencies throughout your app, use `dip.resolve()`, like this:
|
||||
|
||||
```swift
|
||||
struct WebService {
|
||||
let env: EnvironmentType = Dependency.resolve()
|
||||
let env: EnvironmentType = dip.resolve()
|
||||
func sendRequest(path: String, …) {
|
||||
// ... use stuff like env.baseURL here
|
||||
}
|
||||
}
|
||||
|
||||
struct SomeViewModel {
|
||||
let ws: WebServiceType = Dependency.resolve()
|
||||
let ws: WebServiceType = dip.resolve()
|
||||
var friendsProvider: FriendsProviderType
|
||||
init(userName: String) {
|
||||
friendsProvider = Dependency.resolve(userName)
|
||||
friendsProvider = dip.resolve(userName)
|
||||
}
|
||||
func foo() {
|
||||
ws.someMethodDeclaredOnWebServiceType()
|
||||
|
||||
+39
-36
@@ -8,67 +8,75 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public class Dependency {
|
||||
public typealias TagType = String
|
||||
typealias InstanceType = Any
|
||||
typealias InstanceFactory = TagType?->InstanceType
|
||||
/**
|
||||
* Internal representation of a key to associate protocols & tags to an instance factory
|
||||
*/
|
||||
private struct ProtoTagKey<TagType : Equatable> : Hashable, Equatable, CustomDebugStringConvertible {
|
||||
var protocolType: Any.Type
|
||||
var associatedTag: TagType?
|
||||
|
||||
/**
|
||||
* Internal representation of a key to associate protocols & tags to an instance factory
|
||||
*/
|
||||
private struct Key : Hashable, CustomDebugStringConvertible {
|
||||
var protocolType: Any.Type
|
||||
var associatedTag: TagType?
|
||||
|
||||
var hashValue: Int {
|
||||
return "\(protocolType)-\(associatedTag)".hashValue
|
||||
}
|
||||
|
||||
var debugDescription: String {
|
||||
return "type: \(protocolType), tag: \(associatedTag)"
|
||||
}
|
||||
var hashValue: Int {
|
||||
return "\(protocolType)-\(associatedTag)".hashValue
|
||||
}
|
||||
|
||||
private static var dependencies = [Key: InstanceFactory]()
|
||||
var debugDescription: String {
|
||||
return "type: \(protocolType), tag: \(associatedTag)"
|
||||
}
|
||||
}
|
||||
|
||||
private func ==<T>(lhs: ProtoTagKey<T>, rhs: ProtoTagKey<T>) -> Bool {
|
||||
return lhs.protocolType == rhs.protocolType && lhs.associatedTag == rhs.associatedTag
|
||||
}
|
||||
|
||||
// MARK: - DependencyContainer
|
||||
|
||||
public class DependencyContainer<TagType : Equatable> {
|
||||
typealias InstanceType = Any
|
||||
typealias InstanceFactory = TagType?->InstanceType
|
||||
private typealias Key = ProtoTagKey<TagType>
|
||||
|
||||
// MARK: - Reset all dependencies
|
||||
private var dependencies = [Key : InstanceFactory]()
|
||||
|
||||
public static func reset() {
|
||||
public init() {}
|
||||
|
||||
// MARK: Reset all dependencies
|
||||
|
||||
public func reset() {
|
||||
dependencies.removeAll()
|
||||
}
|
||||
|
||||
// MARK: - Register dependencies
|
||||
// MARK: Register dependencies
|
||||
|
||||
/// Register a TagType?->T factory (which takes the tag as parameter)
|
||||
public static func register<T : Any>(tag: TagType? = nil, instanceFactory: TagType?->T) {
|
||||
public func register<T : Any>(tag: TagType? = nil, factory: TagType?->T) {
|
||||
let key = Key(protocolType: T.self, associatedTag: tag)
|
||||
dependencies[key] = { instanceFactory($0) }
|
||||
dependencies[key] = { factory($0) }
|
||||
}
|
||||
|
||||
/// Register a Void->T factory (which don't care about the tag used)
|
||||
public static func register<T : Any>(tag: TagType? = nil, instanceFactory: Void->T) {
|
||||
public func register<T : Any>(tag: TagType? = nil, factory: Void->T) {
|
||||
let key = Key(protocolType: T.self, associatedTag: tag)
|
||||
dependencies[key] = { _ in instanceFactory() }
|
||||
dependencies[key] = { _ in factory() }
|
||||
}
|
||||
|
||||
/// Register a Singleton instance
|
||||
public static func register<T : Any>(tag: TagType? = nil, @autoclosure(escaping) instance instanceFactory: Void->T) {
|
||||
public func register<T : Any>(tag: TagType? = nil, @autoclosure(escaping) instance factory: Void->T) {
|
||||
let key = Key(protocolType: T.self, associatedTag: tag)
|
||||
// FIXME: Make it thread-safe
|
||||
dependencies[key] = { _ in
|
||||
let instance = instanceFactory()
|
||||
dependencies[key] = { _ in return instance }
|
||||
let instance = factory()
|
||||
self.dependencies[key] = { _ in return instance }
|
||||
return instance
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Resolve dependencies
|
||||
// MARK: Resolve dependencies
|
||||
|
||||
/// Resolve a dependency
|
||||
///
|
||||
/// **Note** If a tag is given, it will try to resolve using the tag to generate a specific instance,
|
||||
/// and fallback without the tag if not found with it
|
||||
public static func resolve<T>(tag: TagType? = nil) -> T! {
|
||||
public func resolve<T>(tag: TagType? = nil) -> T! {
|
||||
let key = Key(protocolType: T.self, associatedTag: tag)
|
||||
let nilKey = Key(protocolType: T.self, associatedTag: nil)
|
||||
guard let factory = dependencies[key] ?? dependencies[nilKey] else {
|
||||
@@ -78,8 +86,3 @@ public class Dependency {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Key equality
|
||||
|
||||
private func == (lhs: Dependency.Key, rhs: Dependency.Key) -> Bool {
|
||||
return lhs.protocolType == rhs.protocolType && lhs.associatedTag == rhs.associatedTag
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user