Compare commits

...

75 Commits

Author SHA1 Message Date
Ilya Puchka a1ece4b0ab Merge pull request #126 from AliSoftware/release/5.0.2
Release 5.0.2
2016-10-09 11:33:26 +02:00
Ilya Puchka 0b00e13e00 added hasPrefix method for Linux 2016-10-09 00:34:11 +02:00
Ilya Puchka 4aec626a1f bumped version to 5.0.2 2016-10-08 00:28:05 +02:00
Ilya Puchka d477392deb building against 3.0-RELEASE on Travis on Linux 2016-10-08 00:27:51 +02:00
Ilya Puchka 3b23dc1a6f updated README and CHANGELOG 2016-10-08 00:27:08 +02:00
Ilya Puchka 1d7d0052bf fixed logging 2016-10-07 22:47:07 +02:00
Ilya Puchka b1fee5c1db Merge pull request #125 from AliSoftware/features/swift-3-fixes
Fixed Swift 3 issues
2016-10-07 22:13:41 +02:00
Ilya Puchka e19b65d9c2 fixed issues with reflection of objectes with IUO properties 2016-10-07 19:19:05 +02:00
Ilya Puchka 86bb28da14 Merge branch 'hotfix/pod-fix' into develop 2016-09-16 12:13:30 +02:00
Ilya Puchka e4545e3ed3 Merge pull request #124 from AliSoftware/hotfix/pod-fix
Pod hotfix
2016-09-16 12:13:03 +02:00
Ilya Puchka 52455e663c bumped version to 5.0.1 2016-09-15 01:37:25 +02:00
Ilya Puchka 7a10d1e46e fixed linting podspec 2016-09-15 01:00:34 +02:00
Ilya Puchka e95df85503 Update README.md 2016-09-11 21:18:03 +02:00
Ilya Puchka a028c05271 Merge branch 'release/5.0.0' into develop 2016-09-11 20:48:56 +02:00
Ilya Puchka e18a4b131f Merge pull request #123 from AliSoftware/release/5.0.0
Release 5.0.0
2016-09-11 20:46:31 +02:00
Ilya Puchka e2799279ab Updated README 2016-09-11 20:23:40 +02:00
Ilya Puchka ffb61be63c Merge branch 'master' into release/5.0.0 2016-09-11 19:29:20 +02:00
Ilya Puchka 0070522341 bumped version to 5.0.0 2016-09-11 19:12:14 +02:00
Ilya Puchka 6842a016bf updated CHANGELOG 2016-09-11 19:12:14 +02:00
Ilya Puchka 6a6c4a358e lowercased DipError enum cases 2016-09-11 11:29:44 +02:00
Ilya Puchka 734e67f124 playground fix 2016-09-11 11:15:28 +02:00
Ilya Puchka aa46ef79b9 removed deprecated APIs 2016-09-11 11:12:14 +02:00
Ilya Puchka 2d177b7aea lowercased ComponentScope enum cases 2016-09-11 11:07:01 +02:00
Ilya Puchka 3ada18d756 Swift 3 (#120)
Swift 3 migration
2016-09-11 11:01:02 +02:00
Ilya Puchka 2441f096d6 Merge branch 'feature/single_target' into develop 2016-09-11 02:28:52 +02:00
Ilya Puchka f9f2777474 single target 2016-09-11 02:25:27 +02:00
Ilya Puchka 1dca889730 Merge pull request #121 from AliSoftware/feature/public-methods-renamed
Some public methods renamed
2016-09-11 02:05:15 +02:00
Ilya Puchka 86b23d7260 some public methods renamed 2016-09-11 01:48:57 +02:00
Ilya Puchka 85897e562d minor playground docs fixes 2016-09-11 00:38:15 +02:00
Ilya Puchka cdb5f1b901 Merge pull request #118 from AliSoftware/feature/invalid-type-error
Added error when resolved instance has mismatched type
2016-09-10 00:10:26 +02:00
Ilya Puchka 03903931f2 Merge pull request #117 from AliSoftware/feature/simplified-auto-wiring
Simplified auto-wiring
2016-09-06 23:23:23 +02:00
Ilya Puchka 5016ce860c added error for resolving instance with mismatched type 2016-09-06 01:25:16 +02:00
Ilya Puchka 8da6be8cad simplified auto-wiring 2016-09-06 00:40:59 +02:00
Ilya Puchka 873347aed0 fixed constructing context when resolving with containers collaboration 2016-08-29 23:25:02 +02:00
Ilya Puchka 637ff1f916 made Resolvable extension public 2016-08-29 00:41:14 +02:00
Ilya Puchka c8ddfad188 removed unneeded print 2016-08-27 22:35:19 +02:00
Ilya Puchka 22d73210d0 Merge pull request #116 from AliSoftware/feature/inheritance
Properly handling inheritance
2016-08-27 22:31:16 +02:00
Ilya Puchka feeb7b424a added resolveDependencies(_:DependencyContainer) method in Resolvable 2016-08-27 22:05:21 +02:00
Ilya Puchka a6d2a1b1ab fixed resolving inherited auto-injected dependencies 2016-08-27 21:47:10 +02:00
Ilya Puchka fa400b9a50 added missing precondition in implements method 2016-08-27 19:36:27 +02:00
Ilya Puchka 771c993d78 Merge pull request #114 from AliSoftware/feature/type-forwarding-improvements
Improved type forwarding
2016-08-27 00:25:59 +02:00
Ilya Puchka 10d2560b57 Merge pull request #115 from AliSoftware/feature/registering-explicit-type
Optional type parameter in register methods
2016-08-26 22:53:17 +02:00
Ilya Puchka 2887b78944 added optional type parameter to register methods 2016-08-26 21:40:33 +02:00
Ilya Puchka ed6d45e372 Update README.md 2016-08-26 01:39:25 +02:00
Ilya Puchka 7654737a34 Update README.md 2016-08-26 01:35:47 +02:00
Ilya Puchka f1d35a6a96 improved type forwarding
- removed deprecation annotation for register(_:type:tag:)
- added removing previously registered definition when overriding (for proper cleanup)
- fixed calling resolvingProperties set after registering type-forwarding
- improved tests and code comments
2016-08-26 00:38:01 +02:00
Ilya Puchka 0b355e0fbe some internal methods renaming 2016-08-26 00:34:09 +02:00
Ilya Puchka 9a8e189ce7 fixed playground 2016-08-21 17:44:44 +02:00
Ilya Puchka 53ff00f00d Merge pull request #113 from AliSoftware/feature/definition-refactoring
Definition refactoring
2016-08-21 00:47:05 +02:00
Ilya Puchka 1c18eab371 type forwarding with implements method 2016-08-21 00:11:10 +02:00
Ilya Puchka cd47d888aa renamed DefinitionOf to Definition and changed generic parameter type 2016-08-21 00:11:10 +02:00
Ilya Puchka 499b0c1e38 Merge pull request #112 from ilyapuchka/feature/shared-scope-as-default
Made shared scope a default argument value for register methods
2016-08-21 00:09:28 +02:00
Ilya Puchka 6536a2182d Made shared scope a default argument value for register methods 2016-08-20 23:41:13 +02:00
Ilya Puchka e2ae164d3e fixed crashing in DipUI (SR-680) 2016-08-20 02:12:31 +02:00
Ilya Puchka 092afd8a8b Update README.md 2016-08-20 00:58:06 +02:00
Ilya Puchka a7985f949a Merge branch 'release/4.6.1' into develop 2016-08-14 22:32:17 +02:00
Ilya Puchka 967e1a43cb Merge pull request #111 from AliSoftware/release/4.6.1
Release 4.6.1
2016-08-14 22:31:48 +02:00
Ilya Puchka 73225ddd10 bumped version to 4.6.1, updated README and CHANGELOG 2016-08-14 21:41:45 +02:00
Ilya Puchka 2d238265ca Merge pull request #105 from AliSoftware/feature/grand-renaming
Grand renaming
2016-08-14 20:56:26 +02:00
Ilya Puchka cdfbf3dbfe Update README.md 2016-08-07 00:26:51 +02:00
Ilya Puchka 21a3b43d9b renamed resolveDependencies to resolingProperities 2016-07-28 23:58:24 +02:00
Ilya Puchka 8f0f49e790 renamed withArguments to arguments 2016-07-28 23:35:26 +02:00
Ilya Puchka 7c5966ab61 switched tag and scope parameters in register method 2016-07-28 23:35:26 +02:00
Ilya Puchka c41696cd23 some internal methods renaming 2016-07-28 23:35:26 +02:00
Ilya Puchka 6e7a168fb7 renamed properties of DefinitionKey 2016-07-28 23:35:26 +02:00
Ilya Puchka a2efe0abff renamed Prototype and ObjectGraph scopes 2016-07-28 23:35:26 +02:00
Ilya Puchka d876389c19 Update README.md 2016-07-27 23:05:43 +02:00
Ilya Puchka 5c54e07219 Merge pull request #104 from AliSoftware/feature/config-retain-cycle
Some notes about avoiding retain cycle when configuring container
2016-07-27 22:29:48 +02:00
Ilya Puchka 0e32a79d8c added some notes about avoiding retain cycle when configuring container 2016-07-27 22:02:52 +02:00
Ilya Puchka 37c8b3d03d Merge pull request #103 from AliSoftware/feature/shared-singletons
Sharing singletons between collaborating containers
2016-07-27 21:14:54 +02:00
Ilya Puchka 21ea965607 fixed releasing weak singletons when resetting definition 2016-07-27 20:41:37 +02:00
Ilya Puchka 80d8b1ba99 fixed sharing singletons between collaborators 2016-07-27 20:41:37 +02:00
Ilya Puchka 975041933e Update README.md 2016-07-27 02:18:36 +02:00
Ilya Puchka 404b65b633 Update README.md 2016-07-27 02:16:07 +02:00
Ilya Puchka 73a78ed5a0 Merge branch 'release/4.6.0' into develop 2016-07-17 21:59:32 +02:00
77 changed files with 2785 additions and 2229 deletions
+1
View File
@@ -0,0 +1 @@
3.0
+12 -19
View File
@@ -1,24 +1,22 @@
env:
global:
- MODULE_NAME=Dip
matrix:
allow_failures:
- os: linux
include:
- script:
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip-iOS -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip-OSX -sdk macosx -destination 'platform=OS X,arch=x86_64' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip-tvOS -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV 1080p,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild -workspace Dip.xcworkspace -scheme Dip-watchOS -sdk watchsimulator -destination 'platform=watchOS Simulator,name=Apple Watch - 38mm,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty - c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk macosx -destination 'platform=macOS,arch=x86_64' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV 1080p,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild -workspace Dip.xcworkspace -scheme Dip -sdk watchsimulator -destination 'platform=watchOS Simulator,name=Apple Watch - 38mm,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty - c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme DipSampleApp -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- pod lib lint --quick
- pod spec lint
- carthage build --no-skip-current
os: osx
osx_image: xcode7.3
osx_image: xcode8
language: objective-c
before_install:
- gem install cocoapods --version 1.1.0.rc.2 --no-document
- script:
- swift build
- swift build --clean && swift build && swift test
os: linux
dist: trusty
sudo: required
@@ -26,16 +24,11 @@ matrix:
before_install:
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
- cd ..
- export SWIFT_VERSION=swift-DEVELOPMENT-SNAPSHOT-2016-05-09-a
- wget https://swift.org/builds/development/ubuntu1404/$SWIFT_VERSION/$SWIFT_VERSION-ubuntu14.04.tar.gz
- export SWIFT_VERSION=swift-3.0-RELEASE
- wget https://swift.org/builds/swift-3.0-release/ubuntu1404/$SWIFT_VERSION/$SWIFT_VERSION-ubuntu14.04.tar.gz
- tar xzf $SWIFT_VERSION-ubuntu14.04.tar.gz
- export PATH="${PWD}/${SWIFT_VERSION}-ubuntu14.04/usr/bin:${PATH}"
- export SWIFT_RELEASE_VERSION=2.2.1
- export SWIFT_RELEASE_NAME="${SWIFT_RELEASE_VERSION}-RELEASE"
- wget https://swift.org/builds/swift-$SWIFT_RELEASE_VERSION-release/ubuntu1404/swift-$SWIFT_RELEASE_NAME/swift-$SWIFT_RELEASE_NAME-ubuntu14.04.tar.gz
- tar xzf swift-$SWIFT_RELEASE_NAME-ubuntu14.04.tar.gz
- export SWIFT_EXEC="${PWD}/swift-${SWIFT_RELEASE_NAME}-ubuntu14.04/usr/bin/swiftc"
- cd $MODULE_NAME
- cd Dip
notifications:
email: false
+47 -1
View File
@@ -1,5 +1,51 @@
# CHANGELOG
## 5.0.2
#### Fixed
* Fixed Swift 3 issues related to reflection and IUO
[#125](https://github.com/AliSoftware/Dip/issues/125), [@ilyapuchka](https://github.com/ilyapuchka)
## 5.0.1
This release is the same as 5.0.0 and only fixes CocoaPods speck pushed to trunk without macOS, tvOS and watchOS deployment targets. Please use this release instead of 5.0.0 if you integrate Dip via Cocoapods.
## 5.0.0
* Migrated to Swift 3.0
[#120](https://github.com/AliSoftware/Dip/issues/120), [@patrick-lind](https://github.com/patrick-lind), [@mark-urbanthings](https://github.com/mark-urbanthings), [@ilyapuchka](https://github.com/ilyapuchka)
* Renamed `DefinitionOf` to `Definition` and some other source-breaking refactoring.
[#113](https://github.com/AliSoftware/Dip/issues/113), [@ilyapuchka](https://github.com/ilyapuchka)
* Added `invalidType` error when resolved instance does not implement requested type.
[#118](https://github.com/AliSoftware/Dip/issues/118), [@ilyapuchka](https://github.com/ilyapuchka)
* Added optional `type` parameter in register methods to be able to specify type when registering using method literal instead of closure.
[#115](https://github.com/AliSoftware/Dip/issues/115), [@ilyapuchka](https://github.com/ilyapuchka)
* Added `implements` family of methods in to `Definition` to register type-forwarding definitions.
[#114](https://github.com/AliSoftware/Dip/issues/114), [@ilyapuchka](https://github.com/ilyapuchka)
* Shared scope is now the default scope.
[#112](https://github.com/AliSoftware/Dip/issues/112), [@ilyapuchka](https://github.com/ilyapuchka)
* Single target project setup.
[#121](https://github.com/AliSoftware/Dip/issues/121), [@ilyapuchka](https://github.com/ilyapuchka)
* Simplified implementation of auto-wiring.
[#117](https://github.com/AliSoftware/Dip/issues/117), [@ilyapuchka](https://github.com/ilyapuchka)
#### Fixed
* Auto-injected properties inherited from super class are now properly injected when resolving subclass.
Added `resolveDependencies(_:DependencyContainer)` method to `Resolvable` protocol to handle inheritance when resolving.
[#116](https://github.com/AliSoftware/Dip/issues/116), [@ilyapuchka](https://github.com/ilyapuchka)
## 4.6.1
#### Fixed
* Fixed sharing singletons between collaborating containers.
[#103](https://github.com/AliSoftware/Dip/issues/103), [@ilyapuchka](https://github.com/ilyapuchka)
* Renamed some public API's (see release notes for more info).
[#105](https://github.com/AliSoftware/Dip/issues/105), [@ilyapuchka](https://github.com/ilyapuchka)
## 4.6.0
* Containers collaboration. Break your definitions in modules and link them together.
@@ -146,7 +192,7 @@
This code:
```swift
container.register("some tag") { SomeClass() as SomeProtocol }
container.register(tag: "some tag") { SomeClass() as SomeProtocol }
container.resolve("some tag") as SomeProtocol
```
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Dip"
s.version = "4.6.0"
s.version = "5.0.2"
s.summary = "Dependency Injection for Swift made easy."
s.description = <<-DESC
+92 -645
View File
@@ -8,70 +8,24 @@
/* Begin PBXBuildFile section */
0903B3621C161544002241C1 /* Dip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0903B3581C161543002241C1 /* Dip.framework */; };
0903B3821C1615EC002241C1 /* Dip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0903B3781C1615EC002241C1 /* Dip.framework */; };
0903B3B01C1618AF002241C1 /* Dip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0903B3A61C1618AF002241C1 /* Dip.framework */; };
0919F4D31C16417B00DC3B10 /* Dip.h in Headers */ = {isa = PBXBuildFile; fileRef = 0919F4C91C16417000DC3B10 /* Dip.h */; settings = {ATTRIBUTES = (Public, ); }; };
0919F4D41C16417B00DC3B10 /* Dip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CA1C16417000DC3B10 /* Dip.swift */; };
0919F4D51C16417B00DC3B10 /* Definition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4C81C16417000DC3B10 /* Definition.swift */; };
0919F4D61C16417B00DC3B10 /* RuntimeArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CC1C16417000DC3B10 /* RuntimeArguments.swift */; };
0919F4D71C16417C00DC3B10 /* Dip.h in Headers */ = {isa = PBXBuildFile; fileRef = 0919F4C91C16417000DC3B10 /* Dip.h */; settings = {ATTRIBUTES = (Public, ); }; };
0919F4D81C16417C00DC3B10 /* Dip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CA1C16417000DC3B10 /* Dip.swift */; };
0919F4D91C16417C00DC3B10 /* Definition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4C81C16417000DC3B10 /* Definition.swift */; };
0919F4DA1C16417C00DC3B10 /* RuntimeArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CC1C16417000DC3B10 /* RuntimeArguments.swift */; };
0919F4DB1C16417D00DC3B10 /* Dip.h in Headers */ = {isa = PBXBuildFile; fileRef = 0919F4C91C16417000DC3B10 /* Dip.h */; settings = {ATTRIBUTES = (Public, ); }; };
0919F4DC1C16417D00DC3B10 /* Dip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CA1C16417000DC3B10 /* Dip.swift */; };
0919F4DD1C16417D00DC3B10 /* Definition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4C81C16417000DC3B10 /* Definition.swift */; };
0919F4DE1C16417D00DC3B10 /* RuntimeArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CC1C16417000DC3B10 /* RuntimeArguments.swift */; };
0919F4DF1C16417E00DC3B10 /* Dip.h in Headers */ = {isa = PBXBuildFile; fileRef = 0919F4C91C16417000DC3B10 /* Dip.h */; settings = {ATTRIBUTES = (Public, ); }; };
0919F4E01C16417E00DC3B10 /* Dip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CA1C16417000DC3B10 /* Dip.swift */; };
0919F4E11C16417E00DC3B10 /* Definition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4C81C16417000DC3B10 /* Definition.swift */; };
0919F4E21C16417E00DC3B10 /* RuntimeArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CC1C16417000DC3B10 /* RuntimeArguments.swift */; };
0919F4E31C16419300DC3B10 /* DipTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4D01C16417000DC3B10 /* DipTests.swift */; };
0919F4E41C16419300DC3B10 /* DefinitionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CF1C16417000DC3B10 /* DefinitionTests.swift */; };
0919F4E51C16419300DC3B10 /* RuntimeArgumentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4D21C16417000DC3B10 /* RuntimeArgumentsTests.swift */; };
0919F4E61C16419300DC3B10 /* ComponentScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CE1C16417000DC3B10 /* ComponentScopeTests.swift */; };
0919F4E71C16419400DC3B10 /* DipTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4D01C16417000DC3B10 /* DipTests.swift */; };
0919F4E81C16419400DC3B10 /* DefinitionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CF1C16417000DC3B10 /* DefinitionTests.swift */; };
0919F4E91C16419400DC3B10 /* RuntimeArgumentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4D21C16417000DC3B10 /* RuntimeArgumentsTests.swift */; };
0919F4EA1C16419400DC3B10 /* ComponentScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CE1C16417000DC3B10 /* ComponentScopeTests.swift */; };
0919F4EB1C16419500DC3B10 /* DipTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4D01C16417000DC3B10 /* DipTests.swift */; };
0919F4EC1C16419500DC3B10 /* DefinitionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CF1C16417000DC3B10 /* DefinitionTests.swift */; };
0919F4ED1C16419500DC3B10 /* RuntimeArgumentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4D21C16417000DC3B10 /* RuntimeArgumentsTests.swift */; };
0919F4EE1C16419500DC3B10 /* ComponentScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919F4CE1C16417000DC3B10 /* ComponentScopeTests.swift */; };
095A51CF1CEA1664006B957C /* TypeForwardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095A51CE1CEA1664006B957C /* TypeForwardingTests.swift */; };
095A51D01CEA1664006B957C /* TypeForwardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095A51CE1CEA1664006B957C /* TypeForwardingTests.swift */; };
095A51D11CEA1664006B957C /* TypeForwardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095A51CE1CEA1664006B957C /* TypeForwardingTests.swift */; };
095F829C1D043B41008CD706 /* TypeForwarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095F829B1D043B41008CD706 /* TypeForwarding.swift */; };
095F829D1D043BAA008CD706 /* TypeForwarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095F829B1D043B41008CD706 /* TypeForwarding.swift */; };
095F829E1D043BAA008CD706 /* TypeForwarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095F829B1D043B41008CD706 /* TypeForwarding.swift */; };
095F829F1D043BAB008CD706 /* TypeForwarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095F829B1D043B41008CD706 /* TypeForwarding.swift */; };
0982AF0C1C5183A000B62463 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982AF0B1C5183A000B62463 /* Utils.swift */; };
0982AF0D1C5183A000B62463 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982AF0B1C5183A000B62463 /* Utils.swift */; };
0982AF0E1C5183A000B62463 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982AF0B1C5183A000B62463 /* Utils.swift */; };
0982AF0F1C5183A000B62463 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0982AF0B1C5183A000B62463 /* Utils.swift */; };
09873F561C1E0237000C02F6 /* AutoInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09873F551C1E0237000C02F6 /* AutoInjection.swift */; };
09873F771C1E024E000C02F6 /* AutoInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09873F751C1E0249000C02F6 /* AutoInjectionTests.swift */; };
09873F781C1E024E000C02F6 /* AutoInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09873F751C1E0249000C02F6 /* AutoInjectionTests.swift */; };
09873F791C1E024F000C02F6 /* AutoInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09873F751C1E0249000C02F6 /* AutoInjectionTests.swift */; };
09873F7A1C1E0252000C02F6 /* AutoInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09873F551C1E0237000C02F6 /* AutoInjection.swift */; };
09873F7B1C1E0253000C02F6 /* AutoInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09873F551C1E0237000C02F6 /* AutoInjection.swift */; };
09873F7C1C1E0254000C02F6 /* AutoInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09873F551C1E0237000C02F6 /* AutoInjection.swift */; };
09B035FC1C5D2AD6001EA5B7 /* AutoWiringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B035FB1C5D2AD6001EA5B7 /* AutoWiringTests.swift */; };
09B035FD1C5D2AD6001EA5B7 /* AutoWiringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B035FB1C5D2AD6001EA5B7 /* AutoWiringTests.swift */; };
09B035FE1C5D2AD6001EA5B7 /* AutoWiringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B035FB1C5D2AD6001EA5B7 /* AutoWiringTests.swift */; };
09B036001C5D2B83001EA5B7 /* AutoWiring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B035FF1C5D2B83001EA5B7 /* AutoWiring.swift */; };
09B036011C5D2B83001EA5B7 /* AutoWiring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B035FF1C5D2B83001EA5B7 /* AutoWiring.swift */; };
09B036021C5D2B83001EA5B7 /* AutoWiring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B035FF1C5D2B83001EA5B7 /* AutoWiring.swift */; };
09B036031C5D2B83001EA5B7 /* AutoWiring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B035FF1C5D2B83001EA5B7 /* AutoWiring.swift */; };
09C20EC11C8B3BFD009A082B /* ThreadSafetyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C20EBF1C8B3BC3009A082B /* ThreadSafetyTests.swift */; };
09C20EC21C8B3BFE009A082B /* ThreadSafetyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C20EBF1C8B3BC3009A082B /* ThreadSafetyTests.swift */; };
09C20EC31C8B3BFF009A082B /* ThreadSafetyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C20EBF1C8B3BC3009A082B /* ThreadSafetyTests.swift */; };
09D598331C6F9EC100F24D49 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D598321C6F9EC100F24D49 /* Utils.swift */; };
09D598341C6F9EC100F24D49 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D598321C6F9EC100F24D49 /* Utils.swift */; };
09D598351C6F9EC100F24D49 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D598321C6F9EC100F24D49 /* Utils.swift */; };
64EC9B511CD0CB4000FF6A4C /* ContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64EC9B501CD0CB4000FF6A4C /* ContextTests.swift */; };
64EC9B521CD0CBB400FF6A4C /* ContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64EC9B501CD0CB4000FF6A4C /* ContextTests.swift */; };
64EC9B531CD0CBB500FF6A4C /* ContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64EC9B501CD0CB4000FF6A4C /* ContextTests.swift */; };
09BD350E1D84E30D00B33E53 /* AutoInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD35041D84E30D00B33E53 /* AutoInjectionTests.swift */; };
09BD350F1D84E30D00B33E53 /* AutoWiringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD35051D84E30D00B33E53 /* AutoWiringTests.swift */; };
09BD35101D84E30D00B33E53 /* ComponentScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD35061D84E30D00B33E53 /* ComponentScopeTests.swift */; };
09BD35111D84E30D00B33E53 /* ContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD35071D84E30D00B33E53 /* ContextTests.swift */; };
09BD35121D84E30D00B33E53 /* DefinitionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD35081D84E30D00B33E53 /* DefinitionTests.swift */; };
09BD35131D84E30D00B33E53 /* DipTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD35091D84E30D00B33E53 /* DipTests.swift */; };
09BD35141D84E30D00B33E53 /* RuntimeArgumentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD350A1D84E30D00B33E53 /* RuntimeArgumentsTests.swift */; };
09BD35151D84E30D00B33E53 /* ThreadSafetyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD350B1D84E30D00B33E53 /* ThreadSafetyTests.swift */; };
09BD35161D84E30D00B33E53 /* TypeForwardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD350C1D84E30D00B33E53 /* TypeForwardingTests.swift */; };
09BD35171D84E30D00B33E53 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD350D1D84E30D00B33E53 /* Utils.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -82,50 +36,31 @@
remoteGlobalIDString = 0903B3571C161543002241C1;
remoteInfo = "Dip-OSX";
};
0903B3831C1615EC002241C1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 094526881BEA1CFF0034E72A /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0903B3771C1615EC002241C1;
remoteInfo = "Dip-iOS";
};
0903B3B11C1618AF002241C1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 094526881BEA1CFF0034E72A /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0903B3A51C1618AF002241C1;
remoteInfo = "Dip-tvOS";
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
0903B3581C161543002241C1 /* Dip.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dip.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0903B3611C161543002241C1 /* Dip-OSXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Dip-OSXTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
0903B3781C1615EC002241C1 /* Dip.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dip.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0903B3811C1615EC002241C1 /* Dip-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Dip-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
0903B3A61C1618AF002241C1 /* Dip.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dip.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0903B3AF1C1618AF002241C1 /* Dip-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Dip-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
0903B4041C162862002241C1 /* Dip.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dip.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0903B3611C161543002241C1 /* DipTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DipTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
0919F4C81C16417000DC3B10 /* Definition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Definition.swift; path = ../../Sources/Definition.swift; sourceTree = "<group>"; };
0919F4C91C16417000DC3B10 /* Dip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dip.h; sourceTree = "<group>"; };
0919F4CA1C16417000DC3B10 /* Dip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Dip.swift; path = ../../Sources/Dip.swift; sourceTree = "<group>"; };
0919F4CB1C16417000DC3B10 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0919F4CC1C16417000DC3B10 /* RuntimeArguments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RuntimeArguments.swift; path = ../../Sources/RuntimeArguments.swift; sourceTree = "<group>"; };
0919F4CE1C16417000DC3B10 /* ComponentScopeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ComponentScopeTests.swift; path = ../../Tests/Dip/ComponentScopeTests.swift; sourceTree = "<group>"; };
0919F4CF1C16417000DC3B10 /* DefinitionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DefinitionTests.swift; path = ../../Tests/Dip/DefinitionTests.swift; sourceTree = "<group>"; };
0919F4D01C16417000DC3B10 /* DipTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DipTests.swift; path = ../../Tests/Dip/DipTests.swift; sourceTree = "<group>"; };
0919F4D11C16417000DC3B10 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0919F4D21C16417000DC3B10 /* RuntimeArgumentsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RuntimeArgumentsTests.swift; path = ../../Tests/Dip/RuntimeArgumentsTests.swift; sourceTree = "<group>"; };
095A51CE1CEA1664006B957C /* TypeForwardingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeForwardingTests.swift; sourceTree = "<group>"; };
095F829B1D043B41008CD706 /* TypeForwarding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TypeForwarding.swift; path = ../../Sources/TypeForwarding.swift; sourceTree = "<group>"; };
0982AF0B1C5183A000B62463 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = ../../Sources/Utils.swift; sourceTree = "<group>"; };
09873F551C1E0237000C02F6 /* AutoInjection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AutoInjection.swift; path = ../../Sources/AutoInjection.swift; sourceTree = "<group>"; };
09873F751C1E0249000C02F6 /* AutoInjectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AutoInjectionTests.swift; path = ../../Tests/Dip/AutoInjectionTests.swift; sourceTree = "<group>"; };
09B035FB1C5D2AD6001EA5B7 /* AutoWiringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AutoWiringTests.swift; path = ../../Tests/Dip/AutoWiringTests.swift; sourceTree = "<group>"; };
09B035FF1C5D2B83001EA5B7 /* AutoWiring.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AutoWiring.swift; path = ../../Sources/AutoWiring.swift; sourceTree = "<group>"; };
09C20EBF1C8B3BC3009A082B /* ThreadSafetyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ThreadSafetyTests.swift; path = ../../Tests/Dip/ThreadSafetyTests.swift; sourceTree = "<group>"; };
09D598321C6F9EC100F24D49 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = ../../Tests/Dip/Utils.swift; sourceTree = "<group>"; };
64EC9B501CD0CB4000FF6A4C /* ContextTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContextTests.swift; path = ../../Tests/Dip/ContextTests.swift; sourceTree = "<group>"; };
09BD35041D84E30D00B33E53 /* AutoInjectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AutoInjectionTests.swift; path = ../../Tests/DipTests/AutoInjectionTests.swift; sourceTree = "<group>"; };
09BD35051D84E30D00B33E53 /* AutoWiringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AutoWiringTests.swift; path = ../../Tests/DipTests/AutoWiringTests.swift; sourceTree = "<group>"; };
09BD35061D84E30D00B33E53 /* ComponentScopeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComponentScopeTests.swift; path = ../../Tests/DipTests/ComponentScopeTests.swift; sourceTree = "<group>"; };
09BD35071D84E30D00B33E53 /* ContextTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContextTests.swift; path = ../../Tests/DipTests/ContextTests.swift; sourceTree = "<group>"; };
09BD35081D84E30D00B33E53 /* DefinitionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DefinitionTests.swift; path = ../../Tests/DipTests/DefinitionTests.swift; sourceTree = "<group>"; };
09BD35091D84E30D00B33E53 /* DipTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DipTests.swift; path = ../../Tests/DipTests/DipTests.swift; sourceTree = "<group>"; };
09BD350A1D84E30D00B33E53 /* RuntimeArgumentsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RuntimeArgumentsTests.swift; path = ../../Tests/DipTests/RuntimeArgumentsTests.swift; sourceTree = "<group>"; };
09BD350B1D84E30D00B33E53 /* ThreadSafetyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ThreadSafetyTests.swift; path = ../../Tests/DipTests/ThreadSafetyTests.swift; sourceTree = "<group>"; };
09BD350C1D84E30D00B33E53 /* TypeForwardingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TypeForwardingTests.swift; path = ../../Tests/DipTests/TypeForwardingTests.swift; sourceTree = "<group>"; };
09BD350D1D84E30D00B33E53 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = ../../Tests/DipTests/Utils.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -144,43 +79,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3741C1615EC002241C1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B37E1C1615EC002241C1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0903B3821C1615EC002241C1 /* Dip.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3A21C1618AF002241C1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3AC1C1618AF002241C1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0903B3B01C1618AF002241C1 /* Dip.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B4001C162862002241C1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -203,16 +101,16 @@
0919F4CD1C16417000DC3B10 /* DipTests */ = {
isa = PBXGroup;
children = (
0919F4D01C16417000DC3B10 /* DipTests.swift */,
64EC9B501CD0CB4000FF6A4C /* ContextTests.swift */,
0919F4CF1C16417000DC3B10 /* DefinitionTests.swift */,
0919F4D21C16417000DC3B10 /* RuntimeArgumentsTests.swift */,
0919F4CE1C16417000DC3B10 /* ComponentScopeTests.swift */,
09873F751C1E0249000C02F6 /* AutoInjectionTests.swift */,
09C20EBF1C8B3BC3009A082B /* ThreadSafetyTests.swift */,
09B035FB1C5D2AD6001EA5B7 /* AutoWiringTests.swift */,
095A51CE1CEA1664006B957C /* TypeForwardingTests.swift */,
09D598321C6F9EC100F24D49 /* Utils.swift */,
09BD35041D84E30D00B33E53 /* AutoInjectionTests.swift */,
09BD35051D84E30D00B33E53 /* AutoWiringTests.swift */,
09BD35061D84E30D00B33E53 /* ComponentScopeTests.swift */,
09BD35071D84E30D00B33E53 /* ContextTests.swift */,
09BD35081D84E30D00B33E53 /* DefinitionTests.swift */,
09BD35091D84E30D00B33E53 /* DipTests.swift */,
09BD350A1D84E30D00B33E53 /* RuntimeArgumentsTests.swift */,
09BD350B1D84E30D00B33E53 /* ThreadSafetyTests.swift */,
09BD350C1D84E30D00B33E53 /* TypeForwardingTests.swift */,
09BD350D1D84E30D00B33E53 /* Utils.swift */,
0919F4D11C16417000DC3B10 /* Info.plist */,
);
path = DipTests;
@@ -233,12 +131,7 @@
isa = PBXGroup;
children = (
0903B3581C161543002241C1 /* Dip.framework */,
0903B3611C161543002241C1 /* Dip-OSXTests.xctest */,
0903B3781C1615EC002241C1 /* Dip.framework */,
0903B3811C1615EC002241C1 /* Dip-iOSTests.xctest */,
0903B3A61C1618AF002241C1 /* Dip.framework */,
0903B3AF1C1618AF002241C1 /* Dip-tvOSTests.xctest */,
0903B4041C162862002241C1 /* Dip.framework */,
0903B3611C161543002241C1 /* DipTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@@ -254,36 +147,12 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3751C1615EC002241C1 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
0919F4D71C16417C00DC3B10 /* Dip.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3A31C1618AF002241C1 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
0919F4DB1C16417D00DC3B10 /* Dip.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B4011C162862002241C1 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
0919F4DF1C16417E00DC3B10 /* Dip.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
0903B3571C161543002241C1 /* Dip-OSX */ = {
0903B3571C161543002241C1 /* Dip */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0903B36D1C161544002241C1 /* Build configuration list for PBXNativeTarget "Dip-OSX" */;
buildConfigurationList = 0903B36D1C161544002241C1 /* Build configuration list for PBXNativeTarget "Dip" */;
buildPhases = (
0903B3531C161543002241C1 /* Sources */,
0903B3541C161543002241C1 /* Frameworks */,
@@ -294,14 +163,14 @@
);
dependencies = (
);
name = "Dip-OSX";
name = Dip;
productName = "Dip-OSX";
productReference = 0903B3581C161543002241C1 /* Dip.framework */;
productType = "com.apple.product-type.framework";
};
0903B3601C161543002241C1 /* Dip-OSXTests */ = {
0903B3601C161543002241C1 /* DipTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0903B36E1C161544002241C1 /* Build configuration list for PBXNativeTarget "Dip-OSXTests" */;
buildConfigurationList = 0903B36E1C161544002241C1 /* Build configuration list for PBXNativeTarget "DipTests" */;
buildPhases = (
0903B35D1C161543002241C1 /* Sources */,
0903B35E1C161543002241C1 /* Frameworks */,
@@ -312,131 +181,28 @@
dependencies = (
0903B3641C161544002241C1 /* PBXTargetDependency */,
);
name = "Dip-OSXTests";
name = DipTests;
productName = "Dip-OSXTests";
productReference = 0903B3611C161543002241C1 /* Dip-OSXTests.xctest */;
productReference = 0903B3611C161543002241C1 /* DipTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
0903B3771C1615EC002241C1 /* Dip-iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0903B3891C1615EC002241C1 /* Build configuration list for PBXNativeTarget "Dip-iOS" */;
buildPhases = (
0903B3731C1615EC002241C1 /* Sources */,
0903B3741C1615EC002241C1 /* Frameworks */,
0903B3751C1615EC002241C1 /* Headers */,
0903B3761C1615EC002241C1 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "Dip-iOS";
productName = "Dip-iOS";
productReference = 0903B3781C1615EC002241C1 /* Dip.framework */;
productType = "com.apple.product-type.framework";
};
0903B3801C1615EC002241C1 /* Dip-iOSTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0903B38C1C1615EC002241C1 /* Build configuration list for PBXNativeTarget "Dip-iOSTests" */;
buildPhases = (
0903B37D1C1615EC002241C1 /* Sources */,
0903B37E1C1615EC002241C1 /* Frameworks */,
0903B37F1C1615EC002241C1 /* Resources */,
);
buildRules = (
);
dependencies = (
0903B3841C1615EC002241C1 /* PBXTargetDependency */,
);
name = "Dip-iOSTests";
productName = "Dip-iOSTests";
productReference = 0903B3811C1615EC002241C1 /* Dip-iOSTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
0903B3A51C1618AF002241C1 /* Dip-tvOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0903B3B71C1618AF002241C1 /* Build configuration list for PBXNativeTarget "Dip-tvOS" */;
buildPhases = (
0903B3A11C1618AF002241C1 /* Sources */,
0903B3A21C1618AF002241C1 /* Frameworks */,
0903B3A31C1618AF002241C1 /* Headers */,
0903B3A41C1618AF002241C1 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "Dip-tvOS";
productName = "Dip-tvOS";
productReference = 0903B3A61C1618AF002241C1 /* Dip.framework */;
productType = "com.apple.product-type.framework";
};
0903B3AE1C1618AF002241C1 /* Dip-tvOSTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0903B3BA1C1618AF002241C1 /* Build configuration list for PBXNativeTarget "Dip-tvOSTests" */;
buildPhases = (
0903B3AB1C1618AF002241C1 /* Sources */,
0903B3AC1C1618AF002241C1 /* Frameworks */,
0903B3AD1C1618AF002241C1 /* Resources */,
);
buildRules = (
);
dependencies = (
0903B3B21C1618AF002241C1 /* PBXTargetDependency */,
);
name = "Dip-tvOSTests";
productName = "Dip-tvOSTests";
productReference = 0903B3AF1C1618AF002241C1 /* Dip-tvOSTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
0903B4031C162862002241C1 /* Dip-watchOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0903B4091C162862002241C1 /* Build configuration list for PBXNativeTarget "Dip-watchOS" */;
buildPhases = (
0903B3FF1C162862002241C1 /* Sources */,
0903B4001C162862002241C1 /* Frameworks */,
0903B4011C162862002241C1 /* Headers */,
0903B4021C162862002241C1 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "Dip-watchOS";
productName = "Dip-watchOS";
productReference = 0903B4041C162862002241C1 /* Dip.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
094526881BEA1CFF0034E72A /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0710;
LastUpgradeCheck = 0710;
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = AliSoftware;
TargetAttributes = {
0903B3571C161543002241C1 = {
CreatedOnToolsVersion = 7.1.1;
LastSwiftMigration = 0800;
};
0903B3601C161543002241C1 = {
CreatedOnToolsVersion = 7.1.1;
};
0903B3771C1615EC002241C1 = {
CreatedOnToolsVersion = 7.1.1;
};
0903B3801C1615EC002241C1 = {
CreatedOnToolsVersion = 7.1.1;
};
0903B3A51C1618AF002241C1 = {
CreatedOnToolsVersion = 7.1.1;
};
0903B3AE1C1618AF002241C1 = {
CreatedOnToolsVersion = 7.1.1;
};
0903B4031C162862002241C1 = {
CreatedOnToolsVersion = 7.1.1;
LastSwiftMigration = 0800;
};
};
};
@@ -452,13 +218,8 @@
projectDirPath = "";
projectRoot = "";
targets = (
0903B3571C161543002241C1 /* Dip-OSX */,
0903B3601C161543002241C1 /* Dip-OSXTests */,
0903B3771C1615EC002241C1 /* Dip-iOS */,
0903B3801C1615EC002241C1 /* Dip-iOSTests */,
0903B3A51C1618AF002241C1 /* Dip-tvOS */,
0903B3AE1C1618AF002241C1 /* Dip-tvOSTests */,
0903B4031C162862002241C1 /* Dip-watchOS */,
0903B3571C161543002241C1 /* Dip */,
0903B3601C161543002241C1 /* DipTests */,
);
};
/* End PBXProject section */
@@ -478,41 +239,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3761C1615EC002241C1 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B37F1C1615EC002241C1 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3A41C1618AF002241C1 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3AD1C1618AF002241C1 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B4021C162862002241C1 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -534,92 +260,16 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0919F4E61C16419300DC3B10 /* ComponentScopeTests.swift in Sources */,
09C20EC11C8B3BFD009A082B /* ThreadSafetyTests.swift in Sources */,
0919F4E41C16419300DC3B10 /* DefinitionTests.swift in Sources */,
09D598331C6F9EC100F24D49 /* Utils.swift in Sources */,
09B035FC1C5D2AD6001EA5B7 /* AutoWiringTests.swift in Sources */,
0919F4E31C16419300DC3B10 /* DipTests.swift in Sources */,
0919F4E51C16419300DC3B10 /* RuntimeArgumentsTests.swift in Sources */,
09873F771C1E024E000C02F6 /* AutoInjectionTests.swift in Sources */,
095A51CF1CEA1664006B957C /* TypeForwardingTests.swift in Sources */,
64EC9B511CD0CB4000FF6A4C /* ContextTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3731C1615EC002241C1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0982AF0D1C5183A000B62463 /* Utils.swift in Sources */,
0919F4D91C16417C00DC3B10 /* Definition.swift in Sources */,
09B036011C5D2B83001EA5B7 /* AutoWiring.swift in Sources */,
0919F4D81C16417C00DC3B10 /* Dip.swift in Sources */,
095F829D1D043BAA008CD706 /* TypeForwarding.swift in Sources */,
09873F7A1C1E0252000C02F6 /* AutoInjection.swift in Sources */,
0919F4DA1C16417C00DC3B10 /* RuntimeArguments.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B37D1C1615EC002241C1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0919F4EA1C16419400DC3B10 /* ComponentScopeTests.swift in Sources */,
09C20EC21C8B3BFE009A082B /* ThreadSafetyTests.swift in Sources */,
0919F4E81C16419400DC3B10 /* DefinitionTests.swift in Sources */,
09D598341C6F9EC100F24D49 /* Utils.swift in Sources */,
09B035FD1C5D2AD6001EA5B7 /* AutoWiringTests.swift in Sources */,
0919F4E71C16419400DC3B10 /* DipTests.swift in Sources */,
0919F4E91C16419400DC3B10 /* RuntimeArgumentsTests.swift in Sources */,
09873F781C1E024E000C02F6 /* AutoInjectionTests.swift in Sources */,
095A51D01CEA1664006B957C /* TypeForwardingTests.swift in Sources */,
64EC9B521CD0CBB400FF6A4C /* ContextTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3A11C1618AF002241C1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0982AF0E1C5183A000B62463 /* Utils.swift in Sources */,
0919F4DD1C16417D00DC3B10 /* Definition.swift in Sources */,
09B036021C5D2B83001EA5B7 /* AutoWiring.swift in Sources */,
0919F4DC1C16417D00DC3B10 /* Dip.swift in Sources */,
095F829E1D043BAA008CD706 /* TypeForwarding.swift in Sources */,
09873F7B1C1E0253000C02F6 /* AutoInjection.swift in Sources */,
0919F4DE1C16417D00DC3B10 /* RuntimeArguments.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3AB1C1618AF002241C1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0919F4EE1C16419500DC3B10 /* ComponentScopeTests.swift in Sources */,
09C20EC31C8B3BFF009A082B /* ThreadSafetyTests.swift in Sources */,
0919F4EC1C16419500DC3B10 /* DefinitionTests.swift in Sources */,
09D598351C6F9EC100F24D49 /* Utils.swift in Sources */,
09B035FE1C5D2AD6001EA5B7 /* AutoWiringTests.swift in Sources */,
0919F4EB1C16419500DC3B10 /* DipTests.swift in Sources */,
0919F4ED1C16419500DC3B10 /* RuntimeArgumentsTests.swift in Sources */,
09873F791C1E024F000C02F6 /* AutoInjectionTests.swift in Sources */,
095A51D11CEA1664006B957C /* TypeForwardingTests.swift in Sources */,
64EC9B531CD0CBB500FF6A4C /* ContextTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0903B3FF1C162862002241C1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0982AF0F1C5183A000B62463 /* Utils.swift in Sources */,
0919F4E11C16417E00DC3B10 /* Definition.swift in Sources */,
09B036031C5D2B83001EA5B7 /* AutoWiring.swift in Sources */,
0919F4E01C16417E00DC3B10 /* Dip.swift in Sources */,
095F829F1D043BAB008CD706 /* TypeForwarding.swift in Sources */,
09873F7C1C1E0254000C02F6 /* AutoInjection.swift in Sources */,
0919F4E21C16417E00DC3B10 /* RuntimeArguments.swift in Sources */,
09BD35141D84E30D00B33E53 /* RuntimeArgumentsTests.swift in Sources */,
09BD35151D84E30D00B33E53 /* ThreadSafetyTests.swift in Sources */,
09BD35121D84E30D00B33E53 /* DefinitionTests.swift in Sources */,
09BD350F1D84E30D00B33E53 /* AutoWiringTests.swift in Sources */,
09BD35111D84E30D00B33E53 /* ContextTests.swift in Sources */,
09BD35171D84E30D00B33E53 /* Utils.swift in Sources */,
09BD35131D84E30D00B33E53 /* DipTests.swift in Sources */,
09BD35101D84E30D00B33E53 /* ComponentScopeTests.swift in Sources */,
09BD350E1D84E30D00B33E53 /* AutoInjectionTests.swift in Sources */,
09BD35161D84E30D00B33E53 /* TypeForwardingTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -628,19 +278,9 @@
/* Begin PBXTargetDependency section */
0903B3641C161544002241C1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0903B3571C161543002241C1 /* Dip-OSX */;
target = 0903B3571C161543002241C1 /* Dip */;
targetProxy = 0903B3631C161544002241C1 /* PBXContainerItemProxy */;
};
0903B3841C1615EC002241C1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0903B3771C1615EC002241C1 /* Dip-iOS */;
targetProxy = 0903B3831C1615EC002241C1 /* PBXContainerItemProxy */;
};
0903B3B21C1618AF002241C1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0903B3A51C1618AF002241C1 /* Dip-tvOS */;
targetProxy = 0903B3B11C1618AF002241C1 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
@@ -661,11 +301,9 @@
"iOS=1",
);
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.9;
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-OSX";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.Dip;
PRODUCT_NAME = Dip;
SDKROOT = macosx;
SKIP_INSTALL = YES;
};
name = Debug;
@@ -682,11 +320,9 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.9;
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-OSX";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.Dip;
PRODUCT_NAME = Dip;
SDKROOT = macosx;
SKIP_INSTALL = YES;
};
name = Release;
@@ -694,188 +330,31 @@
0903B36B1C161544002241C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=*]" = "";
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = DipTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-OSXTests";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
0903B36C1C161544002241C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=*]" = "";
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = DipTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-OSXTests";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
};
name = Release;
};
0903B38A1C1615EC002241C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-iOS";
PRODUCT_NAME = Dip;
SKIP_INSTALL = YES;
};
name = Debug;
};
0903B38B1C1615EC002241C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-iOS";
PRODUCT_NAME = Dip;
SKIP_INSTALL = YES;
};
name = Release;
};
0903B38D1C1615EC002241C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
INFOPLIST_FILE = DipTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-iOSTests";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
0903B38E1C1615EC002241C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
INFOPLIST_FILE = DipTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-iOSTests";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
0903B3B81C1618AF002241C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-tvOS";
PRODUCT_NAME = Dip;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.0;
};
name = Debug;
};
0903B3B91C1618AF002241C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-tvOS";
PRODUCT_NAME = Dip;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.0;
};
name = Release;
};
0903B3BB1C1618AF002241C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
INFOPLIST_FILE = DipTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TVOS_DEPLOYMENT_TARGET = 9.0;
};
name = Debug;
};
0903B3BC1C1618AF002241C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
INFOPLIST_FILE = DipTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TVOS_DEPLOYMENT_TARGET = 9.0;
};
name = Release;
};
0903B40A1C162862002241C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-watchOS";
PRODUCT_NAME = Dip;
SDKROOT = watchos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
name = Debug;
};
0903B40B1C162862002241C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.alisoftware.Dip-watchOS";
PRODUCT_NAME = Dip;
SDKROOT = watchos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
name = Release;
};
@@ -892,13 +371,15 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 4.6.0;
CURRENT_PROJECT_VERSION = 5.0.2;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -918,13 +399,17 @@
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = Dip/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
name = Debug;
};
@@ -941,13 +426,15 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 4.6.0;
CURRENT_PROJECT_VERSION = 5.0.2;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -961,19 +448,24 @@
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = Dip/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
0903B36D1C161544002241C1 /* Build configuration list for PBXNativeTarget "Dip-OSX" */ = {
0903B36D1C161544002241C1 /* Build configuration list for PBXNativeTarget "Dip" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0903B3691C161544002241C1 /* Debug */,
@@ -982,7 +474,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0903B36E1C161544002241C1 /* Build configuration list for PBXNativeTarget "Dip-OSXTests" */ = {
0903B36E1C161544002241C1 /* Build configuration list for PBXNativeTarget "DipTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0903B36B1C161544002241C1 /* Debug */,
@@ -991,51 +483,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0903B3891C1615EC002241C1 /* Build configuration list for PBXNativeTarget "Dip-iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0903B38A1C1615EC002241C1 /* Debug */,
0903B38B1C1615EC002241C1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0903B38C1C1615EC002241C1 /* Build configuration list for PBXNativeTarget "Dip-iOSTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0903B38D1C1615EC002241C1 /* Debug */,
0903B38E1C1615EC002241C1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0903B3B71C1618AF002241C1 /* Build configuration list for PBXNativeTarget "Dip-tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0903B3B81C1618AF002241C1 /* Debug */,
0903B3B91C1618AF002241C1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0903B3BA1C1618AF002241C1 /* Build configuration list for PBXNativeTarget "Dip-tvOSTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0903B3BB1C1618AF002241C1 /* Debug */,
0903B3BC1C1618AF002241C1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0903B4091C162862002241C1 /* Build configuration list for PBXNativeTarget "Dip-watchOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0903B40A1C162862002241C1 /* Debug */,
0903B40B1C162862002241C1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0945268B1BEA1CFF0034E72A /* Build configuration list for PBXProject "Dip" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -1,100 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3771C1615EC002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-iOS"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3801C1615EC002241C1"
BuildableName = "Dip-iOSTests.xctest"
BlueprintName = "Dip-iOSTests"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3771C1615EC002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-iOS"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3771C1615EC002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-iOS"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3771C1615EC002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-iOS"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,99 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3A51C1618AF002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-tvOS"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3AE1C1618AF002241C1"
BuildableName = "Dip-tvOSTests.xctest"
BlueprintName = "Dip-tvOSTests"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3A51C1618AF002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-tvOS"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3A51C1618AF002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-tvOS"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3A51C1618AF002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-tvOS"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,80 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B4031C162862002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-watchOS"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B4031C162862002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-watchOS"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B4031C162862002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-watchOS"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -16,7 +16,21 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3571C161543002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-OSX"
BlueprintName = "Dip"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3601C161543002241C1"
BuildableName = "DipTests.xctest"
BlueprintName = "DipTests"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@@ -26,15 +40,16 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3601C161543002241C1"
BuildableName = "Dip-OSXTests.xctest"
BlueprintName = "Dip-OSXTests"
BuildableName = "DipTests.xctest"
BlueprintName = "DipTests"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</TestableReference>
@@ -44,7 +59,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3571C161543002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-OSX"
BlueprintName = "Dip"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -66,7 +81,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3571C161543002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-OSX"
BlueprintName = "Dip"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</MacroExpansion>
@@ -84,7 +99,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "0903B3571C161543002241C1"
BuildableName = "Dip.framework"
BlueprintName = "Dip-OSX"
BlueprintName = "Dip"
ReferencedContainer = "container:Dip.xcodeproj">
</BuildableReference>
</MacroExpansion>
+176
View File
@@ -0,0 +1,176 @@
[
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 54,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 111,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 168,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 228,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 269,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 332,
"remove": 3,
"text": " ",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 472,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 508,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 613,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 649,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 754,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 808,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 879,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 924,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1092,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1149,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1208,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1265,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1473,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1516,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1569,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1643,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1687,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1762,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1806,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 1848,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 2146,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 2315,
"remove": 6,
"text": "open",
},
{
"file": "/Users/ilya/Documents/Developer/iPhoneProjects/Dip/DipPlayground.playground/Sources/Models.swift",
"offset": 2357,
"remove": 6,
"text": "open",
}
]
@@ -8,7 +8,7 @@ let container = DependencyContainer()
### Auto-Injection
On the previous page you saw how auto-wiring helps us get rid of boilerplate code when registering and resolving components with consturctor injection. Auto-injection solves the same problem for property injection.
On the previous page you saw how auto-wiring helps us to get rid of boilerplate code when registering and resolving components with consturctor injection. Auto-injection solves the same problem for property injection.
Let's say you have following related components:
*/
@@ -31,7 +31,7 @@ container.register() { TrackerImp() as Tracker }
container.register() { LoggerImp() as Logger }
container.register() { ServiceImp() as Service }
.resolveDependencies { container, service in
.resolvingProperties { container, service in
let service = service as! ServiceImp
service.logger = try container.resolve() as Logger
service.tracker = try container.resolve() as Tracker
@@ -47,10 +47,10 @@ With auto-injection your code transforms to this:
*/
class AutoInjectedServiceImp: Service {
private var injectedLogger = Injected<Logger>()
private let injectedLogger = Injected<Logger>()
var logger: Logger? { return injectedLogger.value }
private var injectedTracker = Injected<Tracker>()
private let injectedTracker = Injected<Tracker>()
var tracker: Tracker? { return injectedTracker.value }
}
@@ -83,9 +83,7 @@ container.register { ServerWithRequiredClient() }
do {
let serverWithClient = try container.resolve() as ServerWithRequiredClient
}
catch {
print(error)
}
catch {}
/*:
You can make auto-injected property optional by passing `false` to `required` parameter of `Injected<T>`/`InjectedWeak<T>` constructor. For such properties container will ignore any errors when it resolves this property (or any of its dependencies).
@@ -127,12 +125,12 @@ class ServerClientImp: ServerClient {
The standard way to register such components in `DependencyContainer` will lead to such code:
*/
container.register(.ObjectGraph) {
container.register {
ServerClientImp(server: try container.resolve()) as ServerClient
}
container.register(.ObjectGraph) { ServerImp() as Server }
.resolveDependencies { (container: DependencyContainer, server: Server) in
container.register { ServerImp() as Server }
.resolvingProperties { (container: DependencyContainer, server: Server) in
(server as! ServerImp).client = try container.resolve() as ServerClient
}
@@ -153,8 +151,8 @@ class InjectedClientImp: ServerClient {
var server: Server? { get { return injectedServer.value } }
}
container.register(.ObjectGraph) { InjectedServerImp() as Server }
container.register(.ObjectGraph) { InjectedClientImp() as ServerClient }
container.register { InjectedServerImp() as Server }
container.register { InjectedClientImp() as ServerClient }
let injectedClient = try! container.resolve() as ServerClient
injectedClient.server
@@ -176,7 +174,7 @@ class ViewController: UIViewController {
}
container.register { ViewController() }
.resolveDependencies { container, controller in
.resolvingProperties { container, controller in
controller.logger = try container.resolve() as Logger
controller.tracker = try container.resolve() as Tracker
controller.dataProvider = try container.resolve() as DataProvider
@@ -7,7 +7,7 @@ import UIKit
### Auto-wiring
Among three main DI patterns - _constructor_, _property_ and _method_ injection - construction injection should be your choise by default. Dip makes use of this pattern very simple.
Among three main DI patterns - _constructor_, _property_ and _method_ injection - constructor injection should be your choise by default. Dip makes using this pattern very simple.
Let's say you have some VIPER module with following components:
*/
@@ -28,7 +28,7 @@ class View: UIView, ViewOutput {}
class ServiceImp: Service {}
/*:
VIPER module by its nature consists of a lot of components, wired up using protocols. Using construction injection you can end up with following constructors for presenter and interactor:
VIPER module by its nature consists of a lot of components, wired up using protocols. Using constructor injection you can end up with following constructors for presenter and interactor:
*/
class InteractorImp: Interactor {
@@ -86,10 +86,10 @@ But then to resolve presenter or interactor you will first need to resolve their
*/
let service = try! container.resolve() as Service
let interactor = try! container.resolve(withArguments: service) as Interactor
let interactor = try! container.resolve(arguments: service) as Interactor
let view = try! container.resolve() as ViewOutput
let router = try! container.resolve() as Router
presenter = try! container.resolve(withArguments: view, interactor, router) as Presenter
presenter = try! container.resolve(arguments: view, interactor, router) as Presenter
presenter.interactor.service
/*:
@@ -109,7 +109,7 @@ You don't need to call `resolve` in a factory and care about order of arguments
The only requirement is that all constructor arguments should be registered in the container and there should be no several factories with the same _number_ of arguments registered for the same components.
In very rare case when you have several different factories with different set of runtime arguments registered for the same component, when you try to resolve it container will try to use these factories one by one until one of them succeeds starting with a factory with most numbers of arguments. If it finds two factories with the same number of arguments it will throw an error.
In very rare cases when you have several factories for the same component with different set of runtime arguments, when you try to resolve it container will try to use factory registered for the same type and tag (if provided, otherwise registered without tag) and with the maximum number of runtime arguments. If it finds two factories registered for the same type and tag and with the same number but different types of arguments it will throw an error.
You can use auto-wiring with tags. The tag that you pass to `resolve` method will be used to resolve each of the constructor arguments.
*/
@@ -1,6 +1,7 @@
//: [Previous: Scopes](@previous)
import Dip
import Foundation
let container = DependencyContainer()
@@ -25,7 +26,7 @@ class NetworkClientImp: NetworkClient {
init() {}
}
class Interactor: NetworkClientDelegate {
class Interactor: NSObject, NetworkClientDelegate {
let networkClient: NetworkClient
init(networkClient: NetworkClient) {
self.networkClient = networkClient
@@ -43,12 +44,12 @@ It's very important that _at least one_ of them uses property injection, because
Now you can register those classes in container:
*/
container.register(.ObjectGraph) {
container.register {
Interactor(networkClient: try container.resolve()) as NetworkClientDelegate
}
container.register(.ObjectGraph) { NetworkClientImp() as NetworkClient }
.resolveDependencies { (container, client) -> () in
container.register { NetworkClientImp() as NetworkClient }
.resolvingProperties { (container, client) -> () in
client.delegate = try container.resolve() as NetworkClientDelegate
}
@@ -77,26 +78,26 @@ let networkClient = try! container.resolve() as NetworkClient
networkClient.delegate // delegate was alread released =(
/*:
Note also that we used `.ObjectGraph` scope to register implementations. This is also very important to preserve consistency of objects relationships.
Note also that we used `.shared` scope to register implementations. This is also very important to preserve consistency of objects relationships.
If we would have used `.Prototype` scope for both components then container would not reuse instances and we would have an infinite loop:
If we would have used `.unique` scope for both components then container would not reuse instances and we would have an infinite loop:
- Each attempt to resolve `NetworkClientDelegate` will create new instance of `Interactor`.
- It will resolve `NetworkClient` which will create new instance of `NetworkClientImp`.
- It will try to resolve it's delegate property and that will create new instance of `Interactor`
- And so on and so on.
If we would have used `.Prototype` for one of the components it will lead to the same infinite loop or one of the relationships will be invalid:
If we would have used `.unique` for one of the components it will lead to the same infinite loop or one of the relationships will be invalid:
*/
container.reset()
container.register(.Prototype) {
container.register(.unique) {
Interactor(networkClient: try container.resolve()) as NetworkClientDelegate
}
container.register(.ObjectGraph) { NetworkClientImp() as NetworkClient }
.resolveDependencies { (container, client) -> () in
container.register { NetworkClientImp() as NetworkClient }
.resolvingProperties { (container, client) -> () in
client.delegate = try container.resolve() as NetworkClientDelegate
}
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Timeline
version = "3.0">
<TimelineItems>
</TimelineItems>
</Timeline>
@@ -11,10 +11,10 @@ import Dip
protocol DataStore {}
class CoreDataStore: DataStore {}
class AddEventWireframe {
var eventsListWireframe: EventsListWireframe!
var eventsListWireframe: EventsListWireframe?
}
class EventsListWireframe {
var addEventWireframe: AddEventWireframe!
var addEventWireframe: AddEventWireframe?
let dataStore: DataStore
init(dataStore: DataStore) {
self.dataStore = dataStore
@@ -22,20 +22,17 @@ class EventsListWireframe {
}
let rootContainer = DependencyContainer() { container in
container.register(.Singleton) { CoreDataStore() as DataStore }
let rootContainer = DependencyContainer()
rootContainer.register(.singleton) { CoreDataStore() as DataStore }
let eventsListModule = DependencyContainer()
eventsListModule.register { EventsListWireframe(dataStore: $0) }
.resolvingProperties { container, wireframe in
wireframe.addEventWireframe = try container.resolve()
}
let eventsListModule = DependencyContainer() { container in
container.register(.ObjectGraph) { EventsListWireframe(dataStore: $0) }
.resolveDependencies { container, wireframe in
wireframe.addEventWireframe = try container.resolve()
}
}
let addEventModule = DependencyContainer() { container in
container.register { AddEventWireframe() }
}
let addEventModule = DependencyContainer()
addEventModule.register { AddEventWireframe() }
eventsListModule.collaborate(with: addEventModule, rootContainer)
@@ -51,13 +48,13 @@ eventsListWireframe.addEventWireframe
eventsListModule.reset()
addEventModule.reset()
eventsListModule.register(.ObjectGraph) { EventsListWireframe(dataStore: $0) }
.resolveDependencies { container, wireframe in
eventsListModule.register { EventsListWireframe(dataStore: $0) }
.resolvingProperties { container, wireframe in
wireframe.addEventWireframe = try container.resolve()
}
addEventModule.register(.ObjectGraph) { AddEventWireframe() }
.resolveDependencies { container, wireframe in
addEventModule.register { AddEventWireframe() }
.resolvingProperties { container, wireframe in
wireframe.eventsListWireframe = try container.resolve()
}
@@ -65,7 +62,7 @@ addEventModule.collaborate(with: eventsListModule)
eventsListWireframe = try eventsListModule.resolve() as EventsListWireframe
eventsListWireframe.addEventWireframe
eventsListWireframe.addEventWireframe.eventsListWireframe === eventsListWireframe
eventsListWireframe.addEventWireframe?.eventsListWireframe === eventsListWireframe
/*:
If you try to link container with itself it will be silently ignored. When forwarding request collaborating containers will be iterated in the same order that they were added.
@@ -21,6 +21,9 @@ or using a configuration block:
*/
container = DependencyContainer { container in
//do not forget to use unowned reference if you will need
//to reference container inside definition's factory
unowned let container = container
//register components here
}
@@ -1,9 +1,8 @@
//: [Previous: Registering Components](@previous)
import Dip
let container = DependencyContainer { container in
container.register { ServiceImp1() as Service }
}
let container = DependencyContainer()
container.register { ServiceImp1() as Service }
/*:
@@ -42,6 +41,6 @@ let defaultService = try! container.resolve() as Service
You can use runtime arguments to resolve components. Dip supports up to six arguments. For more details see ["Runtime arguments"](Runtime%20arguments).
*/
container.register { service in ClientImp1(service: service) as Client }
let client = try! container.resolve(withArguments: service) as Client
let client = try! container.resolve(arguments: service) as Client
//: [Next: Runtime Arguments](@next)
@@ -15,18 +15,15 @@ Note that __types__, __number__ and __order__ of arguments matters and you can r
container.register { (url: NSURL, port: Int) in ServiceImp4(name: "1", baseURL: url, port: port) as Service }
container.register { (port: Int, url: NSURL) in ServiceImp4(name: "2", baseURL: url, port: port) as Service }
container.register { (port: Int, url: NSURL?) in ServiceImp4(name: "3", baseURL: url!, port: port) as Service }
container.register { (port: Int, url: NSURL!) in ServiceImp4(name: "4", baseURL: url, port: port) as Service }
let url: NSURL = NSURL(string: "http://example.com")!
let service1 = try! container.resolve(withArguments: url, 80) as Service
let service2 = try! container.resolve(withArguments: 80, url) as Service
let service3 = try! container.resolve(withArguments: 80, NSURL(string: "http://example.com")) as Service
let service4 = try! container.resolve(withArguments: 80, NSURL(string: "http://example.com")! as NSURL!) as Service
let service1 = try! container.resolve(arguments: url, 80) as Service
let service2 = try! container.resolve(arguments: 80, url) as Service
let service3 = try! container.resolve(arguments: 80, NSURL(string: "http://example.com")) as Service
(service1 as! ServiceImp4).name
(service2 as! ServiceImp4).name
(service3 as! ServiceImp4).name
(service4 as! ServiceImp4).name
/*:
Note that all of the services were resolved using different factories.
@@ -35,12 +32,15 @@ _Dip_ supports up to six runtime arguments. If that is not enougth you can exten
*/
extension DependencyContainer {
public func register<T, A, B, C, D, E, F, G>(tag tag: DependencyTagConvertible? = nil, _ scope: ComponentScope = .Prototype, factory: (A, B, C, D, E, F, G) throws -> T) -> DefinitionOf<T, (A, B, C, D, E, F, G) throws -> T> {
return registerFactory(tag: tag, scope: scope, factory: factory, numberOfArguments: 7) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag))
@discardableResult
public func register<T, A, B, C, D, E, F, G>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C, D, E, F, G) throws -> T) -> Definition<T, (A, B, C, D, E, F, G)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 7) { container, tag in
try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag))
}
}
public func resolve<T, A, B, C, D, E, F, G>(tag tag: DependencyTagConvertible? = nil, _ arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F, _ arg7: G) throws -> T {
public func resolve<T, A, B, C, D, E, F, G>(tag: DependencyTagConvertible? = nil, _ arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F, _ arg7: G) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4, arg5, arg6, arg7) }
}
}
@@ -8,35 +8,35 @@ let container = DependencyContainer()
### Scopes
Dip supports three different scopes of objects: _Prototype_, _ObjectGraph_ and _Singleton_.
Dip supports three different scopes of objects: _Unique_, _Shared_ and _Singleton_.
* The `Prototype` scope will make the `DependencyContainer` resolve your type as __a new instance every time__ you call `resolve`. This is the default scope.
* The `ObjectGraph` scope is like `Prototype` scope, but it will make the `DependencyContainer` to reuse resolved instances during one (recursive) call to `resolve` method. When this call returns, all resolved instances will be discarded and next call to `resolve` will produce new instances. This scope should be used to resolve [circular dependencies](Circular%20dependencies).
* The `Unique` scope will make the `DependencyContainer` resolve your type as __a new instance every time__ you call `resolve`. This is the default scope.
* The `Shared` scope is like `Unique` scope, but it will make the `DependencyContainer` to reuse resolved instances during one (recursive) call to `resolve` method. When this call returns, all resolved instances will be discarded and next call to `resolve` will produce new instances. This scope should be used to resolve [circular dependencies](Circular%20dependencies).
* The `Singleton` scope will make the `DependencyContainer` retain the instance once resolved the first time, and reuse it in the next calls to `resolve` during the container lifetime.
* The `EagerSingleton` scope is the same as `Singleton` scope but instances with this cope will be created when you call `bootstrap()` method on the container.
* The `WeakSingleton` scope is the same as `Singleton` scope but instances are stored in container as weak references. This scope can be usefull when you need to recreate object graph without reseting container.
The `Prototype` scope is the default. To set a scope you pass it as an argument to `register` method.
The `Unique` scope is the default. To set a scope you pass it as an argument to `register` method.
*/
container.register { ServiceImp1() as Service }
container.register(tag: "prototype", .Prototype) { ServiceImp1() as Service }
container.register(tag: "object graph", .ObjectGraph) { ServiceImp2() as Service }
container.register(tag: "shared instance", .Singleton) { ServiceImp3() as Service }
container.register(.unique, tag: "prototype") { ServiceImp1() as Service }
container.register(.shared, tag: "object graph") { ServiceImp2() as Service }
container.register(.singleton, tag: "shared instance") { ServiceImp3() as Service }
let service = try! container.resolve() as Service
let anotherService = try! container.resolve() as Service
// They are different instances as the scope defaults to .Prototype
// They are different instances as the scope defaults to .unique
service as! ServiceImp1 === anotherService as! ServiceImp1 // false
let prototypeService = try! container.resolve(tag: "prototype") as Service
let anotherPrototypeService = try! container.resolve(tag: "prototype") as Service
let anotherUniqueService = try! container.resolve(tag: "prototype") as Service
// They are different instances:
prototypeService === anotherPrototypeService // false
prototypeService === anotherUniqueService // false
let graphService = try! container.resolve(tag: "object graph") as Service
let anotherGraphService = try! container.resolve(tag: "object graph") as Service
// still different instances the ObjectGraph scope only keep instances during one (recursive) resolution call,
// still different instances the Shared scope only keep instances during one (recursive) resolution call,
// so the two calls on the two lines above are different calls and use different instances
graphService === anotherGraphService // false
@@ -53,8 +53,8 @@ sharedService as! ServiceImp3 === sameSharedService as! ServiceImp3
*/
var resolvedEagerSingleton = false
let definition = container.register(tag: "eager shared instance", .EagerSingleton) { ServiceImp1() as Service }
.resolveDependencies { _ in resolvedEagerSingleton = true }
let definition = container.register(.eagerSingleton, tag: "eager shared instance") { ServiceImp1() as Service }
.resolvingProperties { _ in resolvedEagerSingleton = true }
try! container.bootstrap()
resolvedEagerSingleton
@@ -33,7 +33,7 @@ class ApiClientSingleton {
}
class MyViewControllerWithSingleton: UIViewController {
override func viewDidAppear(amimated: Bool) {
override func viewDidAppear(_ amimated: Bool) {
super.viewDidAppear(amimated)
ApiClientSingleton.sharedInstance.get("/users") { /* refresh your UI */ }
}
@@ -71,13 +71,13 @@ class MyViewController: UIViewController {
var apiClient: ApiClientProtocol!
override func viewDidAppear(amimated: Bool) {
super.viewDidAppear(amimated)
super.viewDidAppear(_ amimated)
apiClient.get("path") {}
}
convenience init(apiClient: ApiClientProtocol) {
self.init()
self.apiClient = apiClient
self.init()
}
init() {
@@ -90,7 +90,7 @@ class MyViewController: UIViewController {
}
//inject with constructor
let viewController = MyViewController(apiClient: ApiClient())
var viewController = MyViewController(apiClient: ApiClient())
//or with property
viewController.apiClient = ApiClient()
@@ -98,33 +98,13 @@ viewController.apiClient = ApiClient()
With Dip this code can look like this:
*/
let container = DependencyContainer { container in
container.register { ApiClient() as ApiClientProtocol }
}
let container = DependencyContainer()
container.register { ApiClient() as ApiClientProtocol }
class DipViewController: UIViewController {
var apiClient: ApiClientProtocol!
override func viewDidAppear(amimated: Bool) {
super.viewDidAppear(amimated)
apiClient.get("path") {}
}
convenience init(dependencies: DependencyContainer) {
self.init()
self.apiClient = try! dependencies.resolve() as ApiClientProtocol
}
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
var dipController = DipViewController(dependencies: container)
//inject with constructor
viewController = try MyViewController(apiClient: container.resolve())
//or with property
viewController.apiClient = try container.resolve()
/*:
Of cource `DependencyContainer` should not be a singleton too. There is just no need for that because you never should call `DependencyContainer` from inside of your components. That will make it a [service locator antipatter]((http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/)). You may only call `DependencyContainer` from the _Composition root_ - the place where all the components are configured and wired together.
@@ -59,7 +59,7 @@ class FakeService: ServiceType {
func configure(container: DependencyContainer) {
container.register { RealService() as ServiceType }
container.register { Client() }
.resolveDependencies { container, client in
.resolvingProperties { container, client in
client.service = try container.resolve()
}
}
@@ -73,7 +73,7 @@ class MyTests/*: XCTestCase*/ {
Reset container configuration to normal state:
*/
container.reset()
configure(container)
configure(container: container)
}
func testThatDoSomethingIsCalled() {
@@ -27,22 +27,22 @@ extension AddPresenter: AddModuleInterface {}
We can achieve this result by explicitly rosolving concrete types:
*/
container.register(.ObjectGraph) { ListWireframe(addWireFrame: $0, listPresenter: $1) }
container.register(.ObjectGraph) { AddWireframe(addPresenter: $0) }
container.register { ListWireframe(addWireFrame: $0, listPresenter: $1) }
container.register { AddWireframe(addPresenter: $0) }
var listInteractorDefinition = container.register(.ObjectGraph) { ListInteractor() }
.resolveDependencies { container, interactor in
var listInteractorDefinition = container.register { ListInteractor() }
.resolvingProperties { container, interactor in
interactor.output = try container.resolve() as ListPresenter
}
var listPresenterDefinition = container.register(.ObjectGraph) { ListPresenter() }
.resolveDependencies { container, presenter in
var listPresenterDefinition = container.register { ListPresenter() }
.resolvingProperties { container, presenter in
presenter.listInteractor = try container.resolve() as ListInteractor
presenter.listWireframe = try container.resolve()
}
var addPresenterDefinition = container.register(.ObjectGraph) { AddPresenter() }
.resolveDependencies { container, presenter in
var addPresenterDefinition = container.register { AddPresenter() }
.resolvingProperties { container, presenter in
presenter.addModuleDelegate = try container.resolve() as ListPresenter
}
@@ -54,33 +54,34 @@ var listWireframe = listPresenter.listWireframe
listWireframe?.listPresenter === listPresenter
/*:
Alternatively we can use type-forwarding. With type-forwarding we register definition for one (source) type and also for another (forwarded) type. When container will try to resolve forwarded type it will use the same definition as for source type, and (if registered in `ObjectGraph` scope or as a singleton) will reuse the same instance. With that you don't need to resolve concrete types in definitions:
Alternatively we can use type-forwarding. With type-forwarding we register definition for one (source) type and also for another (forwarded) type. When container will try to resolve forwarded type it will use the same definition as for source type, and (if registered in `Shared` scope or as a singleton) will reuse the same instance. With that you don't need to resolve concrete types in definitions:
*/
listInteractorDefinition = container.register(.ObjectGraph) { ListInteractor() }
.resolveDependencies { container, interactor in
listInteractorDefinition = container.register { ListInteractor() }
.resolvingProperties { container, interactor in
interactor.output = try container.resolve()
}
listPresenterDefinition = container.register(.ObjectGraph) { ListPresenter() }
.resolveDependencies { container, presenter in
listPresenterDefinition = container.register { ListPresenter() }
.resolvingProperties { container, presenter in
presenter.listInteractor = try container.resolve()
presenter.listWireframe = try container.resolve()
}
addPresenterDefinition = container.register(.ObjectGraph) { AddPresenter() }
.resolveDependencies { container, presenter in
addPresenterDefinition = container.register { AddPresenter() }
.resolvingProperties { container, presenter in
presenter.addModuleDelegate = try container.resolve()
}
/*:
And now we register definitions for type-forwarding:
*/
container.register(listInteractorDefinition, type: ListInteractorInput.self)
container.register(listPresenterDefinition, type: ListInteractorOutput.self)
container.register(listPresenterDefinition, type: ListModuleInterface.self)
container.register(listPresenterDefinition, type: AddModuleDelegate.self)
listInteractorDefinition
.implements(ListInteractorInput.self)
listPresenterDefinition
.implements(ListInteractorOutput.self)
.implements(ListModuleInterface.self)
.implements(AddModuleDelegate.self)
addPresenter = try! container.resolve() as AddPresenter
listPresenter = addPresenter.addModuleDelegate as! ListPresenter
@@ -97,11 +98,11 @@ listWireframe?.listPresenter === listPresenter
You can also provide `resolveDependencies` block for forwarded definition. First container will call `resolveDependencies` block of the source definition, and then of forwarded definition:
*/
listInteractorDefinition
.resolveDependencies { container, interactor in
.resolvingProperties { container, interactor in
print("resolved ListInteractor")
}
container.register(listInteractorDefinition, type: ListInteractorInput.self)
.resolveDependencies { container, interactor in
let _ = container.register(listInteractorDefinition, type: ListInteractorInput.self)
.resolvingProperties { container, interactor in
print("resolved ListInteractorInput")
}
addPresenter = try! container.resolve() as AddPresenter
+72 -64
View File
@@ -1,12 +1,12 @@
# Dip
[![CI Status](http://img.shields.io/travis/AliSoftware/Dip.svg?style=flat)](https://travis-ci.org/AliSoftware/Dip)
[![CI Status](https://travis-ci.org/AliSoftware/Dip.svg?branch=develop)](https://travis-ci.org/AliSoftware/Dip)
[![Version](https://img.shields.io/cocoapods/v/Dip.svg?style=flat)](http://cocoapods.org/pods/Dip)
[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![License](https://img.shields.io/cocoapods/l/Dip.svg?style=flat)](http://cocoapods.org/pods/Dip)
[![Platform](https://img.shields.io/cocoapods/p/Dip.svg?style=flat)](http://cocoapods.org/pods/Dip)
[![Swift Version](https://img.shields.io/badge/Linux-compatible-4BC51D.svg?style=flat)](https://developer.apple.com/swift)
[![Swift Version](https://img.shields.io/badge/Swift-2.2-F16D39.svg?style=flat)](https://developer.apple.com/swift)
[![Swift Version](https://img.shields.io/badge/Swift-2.2--3.0-F16D39.svg?style=flat)](https://developer.apple.com/swift)
[![Swift Version](https://img.shields.io/badge/Linux-3.0--RELEASE-4BC51D.svg?style=flat)](https://developer.apple.com/swift)
![Animated Dipping GIF](cinnamon-pretzels-caramel-dipping.gif)
_Photo courtesy of [www.kevinandamanda.com](http://www.kevinandamanda.com/recipes/appetizer/homemade-soft-cinnamon-sugar-pretzel-bites-with-salted-caramel-dipping-sauce.html)_
@@ -17,45 +17,12 @@ _Photo courtesy of [www.kevinandamanda.com](http://www.kevinandamanda.com/recipe
It's aimed to be as simple as possible yet provide rich functionality usual for DI containers on other platforms. It's inspired by `.NET`'s [Unity Container](https://msdn.microsoft.com/library/ff647202.aspx) and other DI containers.
* You start by creating `let container = DependencyContainer()` and **registering your dependencies, by associating a _protocol_ or _type_ to a `factory`**.
* Then you can call `container.resolve()` to **resolve an instance of _protocol_ or _type_** using that `DependencyContainer`.
* You start by creating `let container = DependencyContainer()` and **registering your dependencies, by associating a _protocol_ or _type_ to a `factory`** using `container.register { MyService() as Service }`.
* Then you can call `container.resolve() as Service` to **resolve an instance of _protocol_ or _type_** using that `DependencyContainer`.
* You can easily use Dip along with **Storyboards and Nibs** - checkout **[Dip-UI](https://github.com/AliSoftware/Dip-UI)** extensions. There is also a **[code generator](https://github.com/ilyapuchka/dipgen)** that can help to simplify registering new components.
> You can easily use Dip along with Storyboards and Nibs - checkout [Dip-UI](https://github.com/AliSoftware/Dip-UI) extensions.
## Documentation & Usage Examples
Dip is completely [documented](http://cocoadocs.org/docsets/Dip/4.6.0/) and comes with a Playground that lets you try all its features and become familiar with API. You can find it in `Dip.xcworkspace`.
> Note: it may happen that you will need to build Dip framework before playground will be able to use it. For that select `Dip-iOS` scheme and build.
You can find bunch of usage examples in a [wiki](../../wiki).
If your are using [VIPER](https://www.objc.io/issues/13-architecture/viper/) architecture - [here](https://github.com/ilyapuchka/VIPER-SWIFT) is VIPER demo app that uses Dip instead of manual dependency injection.
There are also several blog posts that describe how to use Dip and some of its implementation details:
- [IoC container in Swift](http://ilya.puchka.me/ioc-container-in-swift/)
- [IoC container in Swift. Circular dependencies and auto-injection](http://ilya.puchka.me/ioc-container-in-swift-circular-dependencies-and-auto-injection/)
- [Dependency injection with Dip](http://ilya.puchka.me/dependency-injecinjection-with-dip/)
File an issue if you have any question.
## Features
- **[Scopes](../../wiki/scopes)**. Dip supports 5 different scopes (or life cycle strategies): _Prototype_, _ObjectGraph_, _Singleton_, _EagerSingleton_;
- **[Named definitions](../../wiki/named-definitions)**. You can register different factories for the same protocol or type by registering them with [tags]();
- **[Runtime arguments](../../wiki/runtime-arguments)**. You can register factories that accept up to 6 runtime arguments;
- **[Circular dependencies](../../wiki/circular-dependencies)**. Dip can resolve circular dependencies;
- **[Auto-wiring](../../wiki/auto-wiring)** & **[Auto-injection](../../wiki/auto-injection)**. Dip can infer your components' dependencies injected in constructor and automatically resolve them as well as dependencies injected with properties.
- **[Type forwarding](../../wiki/type-forwarding)**. You can register the same factory to resolve different types.
- **[Storyboards integration](../../wiki/storyboards-integration)**. You can easily use Dip along with storyboards and Xibs without ever referencing container in your view controller's code;
- **Weakly typed components**. Dip can resolve weak types when they are unknown at compile time.
- **[Easy configuration](../../wiki/configuration)**. No complex container hierarchy, no unneeded functionality;
- **Thread safety**. Registering and resolving components is thread safe;
- **Helpful error messages and configuration validation**. You can validate your container configuration. If something can not be resolved at runtime Dip throws an error that completely describes the issue;
## Basic usage
<details>
<summary>Basic usage</summary>
```swift
import Dip
@@ -81,7 +48,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
```
## More sophisticated example
</details>
<details>
<summary>More sophisticated example</summary>
```swift
import Dip
@@ -99,8 +69,11 @@ extension DependencyContainer {
static func configure() -> DependencyContainer {
return DependencyContainer { container in
unowned let container = container
DependencyContainer.uiContainers = [container]
container.register(tag: "ViewController") { ViewController() }
.resolveDependencies { container, controller in
.resolvingProperties { container, controller in
controller.animationsFactory = try container.resolve() as AnimatonsFactory
}
@@ -136,49 +109,84 @@ class ViewController {
```
</details>
## Documentation & Usage Examples
Dip is completely [documented](http://cocoadocs.org/docsets/Dip/5.0.0/) and comes with a Playground that lets you try all its features and become familiar with API. You can find it in `Dip.xcworkspace`.
> Note: it may happen that you will need to build Dip framework before playground will be able to use it. For that select `Dip` scheme and build for iPhone Simulator.
You can find bunch of usage examples and usfull tips in a [wiki](../../wiki).
If your are using [VIPER](https://www.objc.io/issues/13-architecture/viper/) architecture - [here](https://github.com/ilyapuchka/VIPER-SWIFT) is VIPER demo app that uses Dip instead of manual dependency injection.
There are also several blog posts that describe how to use Dip and some of its implementation details:
- [IoC container in Swift](http://ilya.puchka.me/ioc-container-in-swift/)
- [IoC container in Swift. Circular dependencies and auto-injection](http://ilya.puchka.me/ioc-container-in-swift-circular-dependencies-and-auto-injection/)
- [Dependency injection with Dip](http://ilya.puchka.me/dependency-injecinjection-with-dip/)
File an issue if you have any question. Pull requests are warmly welcome too.
## Features
- **[Scopes](../../wiki/scopes)**. Dip supports 5 different scopes (or life cycle strategies): _Unique_, _Shared_, _Singleton_, _EagerSingleton_, _WeakSingleton_;
- **[Auto-wiring](../../wiki/auto-wiring)** & **[Auto-injection](../../wiki/auto-injection)**. Dip can infer your components' dependencies injected in constructor and automatically resolve them as well as dependencies injected with properties.
- **[Resolving optionals](../../wiki/resolving-optionals)**. Dip is able to resolve constructor or property dependencies defined as optionals.
- **[Type forwarding](../../wiki/type-forwarding)**. You can register the same factory to resolve different types implemeted by a single class.
- **[Circular dependencies](../../wiki/circular-dependencies)**. Dip will be able to resolve circular dependencies if you will follow some simple rules;
- **[Storyboards integration](../../wiki/storyboards-integration)**. You can easily use Dip along with storyboards and Xibs without ever referencing container in your view controller's code;
- **[Named definitions](../../wiki/named-definitions)**. You can register different factories for the same protocol or type by registering them with [tags]();
- **[Runtime arguments](../../wiki/runtime-arguments)**. You can register factories that accept up to 6 runtime arguments (and extend it if you need);
- **[Easy configuration](../../wiki/containers-collaboration)** & **Code generation**. No complex containers hierarchy, no unneeded functionality. Tired of writing all registrations by hand? There is a [cool code generator](https://github.com/ilyapuchka/dipgen) that will create them for you. The only thing you need is to annotate your code with some comments.
- **Weakly typed components**. Dip can resolve "weak" types when they are unknown at compile time.
- **Thread safety**. Registering and resolving components is thread safe;
- **Helpful error messages and configuration validation**. You can validate your container configuration. If something can not be resolved at runtime Dip throws an error that completely describes the issue;
## Installation
Since version 4.3.1 Dip is built with Swift 2.2. The latest version built with Swift 2.1 is 4.3.0.
Since version 5.0.0 Dip is built with Swift 3.0. For Swift 2.2-2.3 compatible version use "swift2.3" branch.
Dip is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile:
You can install Dip using your favorite dependency manager:
<details>
<summary>CocoaPods</summary>
```ruby
pod "Dip"
```
> You need at least 1.1.0.rc.2 version of CocoaPods.
If you use [Carthage](https://github.com/Carthage/Carthage) add this line to your Cartfile:
</details>
<details>
<summary>Carthage</summary>
```
github "AliSoftware/Dip"
```
If you use [Swift Package Manager](https://swift.org/package-manager/) add Dip as dependency to you `Package.swift`:
</details>
<details>
<summary>Swift Package Manager</summary>
```swift
let package = Package(
name: "MyPackage",
dependencies: [
.Package(url: "https://github.com/AliSoftware/Dip.git", "4.6.0")
]
)
.Package(url: "https://github.com/AliSoftware/Dip", majorVersion: 5, minor: 0)
```
</details>
## Running tests
On OSX you can run tests from Xcode. On Linux you need to have Swift Package Manager installed and use it to build and run tests:
```
cd Dip
swift build && swift test
```
> Note: Swift Package Manager is destributed with Swift development snapshots only, so it builds packages using Swift 3. To build Dip you will need to build it with Swift 2.2, for that you need to set [`$SWIFT_EXEC`](https://github.com/apple/swift-package-manager#choosing-swift-version) environment variable.
On OSX you can run tests from Xcode. On Linux you need to have Swift Package Manager installed and use it to build and run tests using this command: `swift build --clean && swift build && swift test`
## Credits
This library has been created by [**Olivier Halligon**](olivier@halligon.net).
I'd also like to thank [**Ilya Puchka**](https://twitter.com/ilyapuchka) for his big contribution to it, as he added a lot of great features to it.
This library has been created by [**Olivier Halligon**](olivier@halligon.net) and is maintained by [**Ilya Puchka**](https://twitter.com/ilyapuchka).
**Dip** is available under the **MIT license**. See the `LICENSE` file for more info.
@@ -279,7 +279,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0700;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = AliSoftware;
TargetAttributes = {
0990225E1BC123C000E76F43 = {
@@ -414,6 +414,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipSampleApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
@@ -460,6 +461,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
@@ -496,6 +498,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_VERSION = 3.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
@@ -521,6 +524,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
};
name = Release;
};
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
+2 -2
View File
@@ -16,11 +16,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
private let container = DependencyContainer()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
// Override point for customization after application launch.
//This is a composition root where container is configured and all dependencies are resolved
configureContainer(container)
configure(container: container)
let personProvider = try! container.resolve() as PersonProviderAPI
let starshipProvider = try! container.resolve() as StarshipProviderAPI
+7 -7
View File
@@ -12,8 +12,8 @@ protocol BaseCell {
static var identifier: String { get }
static var nib: UINib? { get }
static func register(tableView: UITableView)
static func dequeueFromTableView(tableView: UITableView, forIndexPath indexPath: NSIndexPath) -> Self
static func register(_ tableView: UITableView)
static func dequeueFromTableView(_ tableView: UITableView, forIndexPath indexPath: IndexPath) -> Self
}
extension BaseCell where Self : UITableViewCell {
@@ -22,16 +22,16 @@ extension BaseCell where Self : UITableViewCell {
}
static var nib: UINib? { return nil }
static func register(tableView: UITableView) {
static func register(_ tableView: UITableView) {
if let cellNib = self.nib {
tableView.registerNib(cellNib, forCellReuseIdentifier: identifier)
tableView.register(cellNib, forCellReuseIdentifier: identifier)
} else {
tableView.registerClass(Self.self as AnyClass, forCellReuseIdentifier: identifier)
tableView.register(Self.self as AnyClass, forCellReuseIdentifier: identifier)
}
}
static func dequeueFromTableView(tableView: UITableView, forIndexPath indexPath: NSIndexPath) -> Self {
return tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) as! Self
static func dequeueFromTableView(_ tableView: UITableView, forIndexPath indexPath: IndexPath) -> Self {
return tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) as! Self
}
}
@@ -0,0 +1,45 @@
//
// BaseCell.swift
// Dip
//
// Created by Olivier Halligon on 10/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
protocol BaseCell {
static var identifier: String { get }
static var nib: UINib? { get }
static func register(_ tableView: UITableView)
static func dequeueFromTableView(_ tableView: UITableView, forIndexPath indexPath: IndexPath) -> Self
}
extension BaseCell where Self : UITableViewCell {
static var identifier: String {
return "\(Self.self)"
}
static var nib: UINib? { return nil }
static func register(_ tableView: UITableView) {
if let cellNib = self.nib {
tableView.register(cellNib, forCellReuseIdentifier: identifier)
} else {
tableView.register(Self.self as AnyClass, forCellReuseIdentifier: identifier)
}
}
<<<<<<< HEAD
static func dequeueFromTableView(tableView: UITableView, forIndexPath indexPath: NSIndexPath) -> Self {
=======
static func dequeueFromTableView(_ tableView: UITableView, forIndexPath indexPath: IndexPath) -> Self {
>>>>>>> feature/swift3
return tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) as! Self
}
}
protocol FillableCell: BaseCell {
associatedtype ObjectType
func fillWithObject(object: ObjectType)
}
@@ -16,22 +16,22 @@ final class PersonCell : UITableViewCell, FillableCell {
@IBOutlet weak var hairLabel: UILabel!
@IBOutlet weak var eyesLabel: UILabel!
let heightFormatter: NSLengthFormatter = {
let f = NSLengthFormatter()
f.forPersonHeightUse = true
let heightFormatter: LengthFormatter = {
let f = LengthFormatter()
f.isForPersonHeightUse = true
return f
}()
let massFormatter: NSMassFormatter = {
let f = NSMassFormatter()
f.forPersonMassUse = true
let massFormatter: MassFormatter = {
let f = MassFormatter()
f.isForPersonMassUse = true
return f
}()
func fillWithObject(person: Person) {
func fillWithObject(object person: Person) {
nameLabel.text = person.name
genderImageView.image = person.gender.flatMap { UIImage(named: $0.rawValue) }
heightLabel.text = heightFormatter.stringFromValue(Double(person.height), unit: .Centimeter)
massLabel.text = massFormatter.stringFromValue(Double(person.mass), unit: .Kilogram)
heightLabel.text = heightFormatter.string(fromValue: Double(person.height), unit: .centimeter)
massLabel.text = massFormatter.string(fromValue: Double(person.mass), unit: .kilogram)
hairLabel.text = person.hairColor
eyesLabel.text = person.eyeColor
}
@@ -0,0 +1,48 @@
//
// UserCell.swift
// Dip
//
// Created by Olivier Halligon on 10/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
final class PersonCell : UITableViewCell, FillableCell {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var genderImageView: UIImageView!
@IBOutlet weak var heightLabel: UILabel!
@IBOutlet weak var massLabel: UILabel!
@IBOutlet weak var hairLabel: UILabel!
@IBOutlet weak var eyesLabel: UILabel!
<<<<<<< HEAD
let heightFormatter: NSLengthFormatter = {
let f = NSLengthFormatter()
f.isForPersonHeightUse = true
return f
}()
let massFormatter: NSMassFormatter = {
let f = NSMassFormatter()
=======
let heightFormatter: LengthFormatter = {
let f = LengthFormatter()
f.isForPersonHeightUse = true
return f
}()
let massFormatter: MassFormatter = {
let f = MassFormatter()
>>>>>>> feature/swift3
f.isForPersonMassUse = true
return f
}()
func fillWithObject(object person: Person) {
nameLabel.text = person.name
genderImageView.image = person.gender.flatMap { UIImage(named: $0.rawValue) }
heightLabel.text = heightFormatter.string(fromValue: Double(person.height), unit: .centimeter)
massLabel.text = massFormatter.string(fromValue: Double(person.mass), unit: .kilogram)
hairLabel.text = person.hairColor
eyesLabel.text = person.eyeColor
}
}
@@ -15,13 +15,13 @@ final class StarshipCell : UITableViewCell, FillableCell {
@IBOutlet weak var crewLabel: UILabel!
@IBOutlet weak var passengersLabel: UILabel!
let numberFormatter = NSNumberFormatter()
let numberFormatter = NumberFormatter()
func fillWithObject(starship: Starship) {
func fillWithObject(object starship: Starship) {
nameLabel.text = starship.name
modelLabel.text = starship.model
manufacturerLabel.text = starship.manufacturer
crewLabel.text = numberFormatter.stringFromNumber(starship.crew)
passengersLabel.text = numberFormatter.stringFromNumber(starship.passengers)
crewLabel.text = numberFormatter.string(from: NSNumber(integerLiteral: starship.crew))
passengersLabel.text = numberFormatter.string(from: NSNumber(integerLiteral: starship.passengers))
}
}
@@ -23,17 +23,17 @@ enum DependencyTags: Int, DependencyTagConvertible {
}
// MARK: Dependency Container for Providers
func configureContainer(dip: DependencyContainer) {
func configure(container dip: DependencyContainer) {
// Register the NetworkLayer, same for everyone here (but we have the ability to register a different one for a specific WebService if we wanted to)
dip.register(.Singleton) { URLSessionNetworkLayer(baseURL: "http://swapi.co/api/")! as NetworkLayer }
dip.register(.singleton) { URLSessionNetworkLayer(baseURL: "http://swapi.co/api/")! as NetworkLayer }
if FAKE_PERSONS {
// 1) Register fake persons provider
//Here we use constructor injection for one of the dependencies property injection for another, and we provide dependencies manually
dip.register() { FakePersonsProvider(dummyProvider: DummyPilotProvider()) as PersonProviderAPI }
.resolveDependencies { (_, resolved: PersonProviderAPI) in
.resolvingProperties { (_, resolved: PersonProviderAPI) in
//here we resolve optional dependencies
//see what happens when you comment this out
(resolved as! FakePersonsProvider).plistProvider = PlistPersonProvider(plist: "mainPilot")
@@ -60,7 +60,7 @@ func configureContainer(dip: DependencyContainer) {
//Here we use constructor injection, but instead of providing dependencies manually container resolves them for us
dip.register() {
FakeStarshipProvider(
dummyProvider: try dip.resolve(tag: DependencyTags.Dummy, withArguments: "Main Pilot"),
dummyProvider: try dip.resolve(tag: DependencyTags.Dummy, arguments: "Main Pilot"),
hardCodedProvider: try dip.resolve(tag: DependencyTags.Hardcoded)) as StarshipProviderAPI
}
@@ -11,12 +11,12 @@ import Foundation
///Provides some dummy Person entities
struct DummyPilotProvider : PersonProviderAPI {
func fetchIDs(completion: [Int] -> Void) {
func fetchIDs(completion: @escaping ([Int]) -> Void) {
completion(Array(0..<5))
}
func fetch(id: Int, completion: Person? -> Void) {
completion(dummyPerson(id))
func fetch(id: Int, completion: @escaping (Person?) -> Void) {
completion(dummyPerson(idx: id))
}
private func dummyPerson(idx: Int) -> Person {
@@ -40,9 +40,9 @@ class PlistPersonProvider : PersonProviderAPI {
init(plist basename: String) {
guard
let path = NSBundle.mainBundle().pathForResource(basename, ofType: "plist"),
let path = Bundle.main.path(forResource: basename, ofType: "plist"),
let list = NSArray(contentsOfFile: path),
peopleDict = list as? [[String:AnyObject]]
let peopleDict = list as? [[String:AnyObject]]
else {
fatalError("PLIST for \(basename) not found")
}
@@ -50,11 +50,11 @@ class PlistPersonProvider : PersonProviderAPI {
self.people = peopleDict.map(PlistPersonProvider.personFromDict)
}
func fetchIDs(completion: [Int] -> Void) {
func fetchIDs(completion: @escaping ([Int]) -> Void) {
completion(Array(0..<people.count))
}
func fetch(id: Int, completion: Person? -> Void) {
func fetch(id: Int, completion: @escaping (Person?) -> Void) {
guard id < people.count else {
completion(nil)
return
@@ -65,12 +65,12 @@ class PlistPersonProvider : PersonProviderAPI {
private static func personFromDict(dict: [String:AnyObject]) -> Person {
guard
let name = dict["name"] as? String,
height = dict["height"] as? Int,
mass = dict["mass"] as? Int,
hairColor = dict["hairColor"] as? String,
eyeColor = dict["eyeColor"] as? String,
genderStr = dict["gender"] as? String,
starshipsIDs = dict["starships"] as? [Int]
let height = dict["height"] as? Int,
let mass = dict["mass"] as? Int,
let hairColor = dict["hairColor"] as? String,
let eyeColor = dict["eyeColor"] as? String,
let genderStr = dict["gender"] as? String,
let starshipsIDs = dict["starships"] as? [Int]
else {
fatalError("Invalid Plist")
}
@@ -98,16 +98,16 @@ class FakePersonsProvider: PersonProviderAPI {
self.dummyProvider = dummyProvider
}
func fetchIDs(completion: [Int] -> Void) {
dummyProvider.fetchIDs(completion)
func fetchIDs(completion: @escaping ([Int]) -> Void) {
dummyProvider.fetchIDs(completion: completion)
}
func fetch(id: Int, completion: Person? -> Void) {
if let plistProvider = plistProvider where id == 0 {
plistProvider.fetch(id, completion: completion)
func fetch(id: Int, completion: @escaping (Person?) -> Void) {
if let plistProvider = plistProvider, id == 0 {
plistProvider.fetch(id: id, completion: completion)
}
else {
dummyProvider.fetch(id, completion: completion)
dummyProvider.fetch(id: id, completion: completion)
}
}
@@ -0,0 +1,126 @@
//
// PlistPersonProvider.swift
// Dip
//
// Created by Ilya Puchka on 12/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
///Provides some dummy Person entities
struct DummyPilotProvider : PersonProviderAPI {
func fetchIDs(completion: ([Int]) -> Void) {
completion(Array(0..<5))
}
<<<<<<< HEAD
func fetch(id: Int, completion: Person? -> Void) {
=======
func fetch(id: Int, completion: (Person?) -> Void) {
>>>>>>> feature/swift3
completion(dummyPerson(idx: id))
}
private func dummyPerson(idx: Int) -> Person {
let colors = ["blue", "brown", "yellow", "orange", "red", "dark"]
let genders: [Gender?] = [Gender.Male, Gender.Female, nil]
return Person(
name: "John Dummy Doe #\(idx)",
height: 150 + (idx*27%40),
mass: 50 + (idx*7%30),
hairColor: colors[idx*3%colors.count],
eyeColor: colors[idx*2%colors.count],
gender: genders[idx%3],
starshipIDs: [idx % 3, 2*idx % 4]
)
}
}
///Provides Person entities reading then from plist file
class PlistPersonProvider : PersonProviderAPI {
let people: [Person]
init(plist basename: String) {
guard
<<<<<<< HEAD
let path = NSBundle.main().pathForResource(basename, ofType: "plist"),
=======
let path = Bundle.main().pathForResource(basename, ofType: "plist"),
>>>>>>> feature/swift3
let list = NSArray(contentsOfFile: path),
peopleDict = list as? [[String:AnyObject]]
else {
fatalError("PLIST for \(basename) not found")
}
self.people = peopleDict.map(PlistPersonProvider.personFromDict)
}
func fetchIDs(completion: ([Int]) -> Void) {
completion(Array(0..<people.count))
}
func fetch(id: Int, completion: (Person?) -> Void) {
guard id < people.count else {
completion(nil)
return
}
completion(people[id])
}
private static func personFromDict(dict: [String:AnyObject]) -> Person {
guard
let name = dict["name"] as? String,
height = dict["height"] as? Int,
mass = dict["mass"] as? Int,
hairColor = dict["hairColor"] as? String,
eyeColor = dict["eyeColor"] as? String,
genderStr = dict["gender"] as? String,
starshipsIDs = dict["starships"] as? [Int]
else {
fatalError("Invalid Plist")
}
return Person(
name: name,
height: height,
mass: mass,
hairColor: hairColor,
eyeColor: eyeColor,
gender: Gender(rawValue: genderStr),
starshipIDs: starshipsIDs
)
}
}
class FakePersonsProvider: PersonProviderAPI {
let dummyProvider: PersonProviderAPI
var plistProvider: PersonProviderAPI!
//In this class we use both constructor injection and property injection,
//nil is a valid local default
init(dummyProvider: PersonProviderAPI) {
self.dummyProvider = dummyProvider
}
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
>>>>>>> feature/swift3
dummyProvider.fetchIDs(completion: completion)
}
func fetch(id: Int, completion: (Person?) -> Void) {
if let plistProvider = plistProvider where id == 0 {
plistProvider.fetch(id: id, completion: completion)
}
else {
dummyProvider.fetch(id: id, completion: completion)
}
}
}
@@ -12,13 +12,13 @@ import Foundation
struct DummyStarshipProvider : StarshipProviderAPI {
var pilotName: String
func fetchIDs(completion: [Int] -> Void) {
func fetchIDs(completion: @escaping ([Int]) -> Void) {
let nbShips = pilotName.characters.count
completion(Array(0..<nbShips))
}
func fetch(id: Int, completion: Starship? -> Void) {
completion(dummyStarship(id))
func fetch(id: Int, completion: @escaping (Starship?) -> Void) {
completion(dummyStarship(idx: id))
}
private func dummyStarship(idx: Int) -> Starship {
@@ -42,11 +42,11 @@ class HardCodedStarshipProvider : StarshipProviderAPI {
Starship(name: "Third Ship", model: "AwesomeShip Cargo", manufacturer: "HardCoded Inc.", crew: 12, passengers: 150, pilotIDs: [2]),
] + Array(4..<75).map { Starship(name: "Ship #\($0)", model: "AwesomeShip Fighter", manufacturer: "HardCoded Inc.", crew: 1, passengers: 2, pilotIDs: [1]) }
func fetchIDs(completion: [Int] -> Void) {
func fetchIDs(completion: @escaping ([Int]) -> Void) {
completion(Array(0..<starships.count))
}
func fetch(id: Int, completion: Starship? -> Void) {
func fetch(id: Int, completion: @escaping (Starship?) -> Void) {
guard id < starships.count else {
completion(nil)
return
@@ -66,16 +66,16 @@ class FakeStarshipProvider: StarshipProviderAPI {
self.hardCodedProvider = hardCodedProvider
}
func fetchIDs(completion: [Int] -> Void) {
hardCodedProvider.fetchIDs(completion)
func fetchIDs(completion: @escaping ([Int]) -> Void) {
hardCodedProvider.fetchIDs(completion: completion)
}
func fetch(id: Int, completion: Starship? -> Void) {
func fetch(id: Int, completion: @escaping (Starship?) -> Void) {
if id == 0 {
dummyProvider.fetch(id, completion: completion)
dummyProvider.fetch(id: id, completion: completion)
}
else {
hardCodedProvider.fetch(id, completion: completion)
hardCodedProvider.fetch(id: id, completion: completion)
}
}
@@ -0,0 +1,92 @@
//
// FakeStarshipProvider.swift
// DipSampleApp
//
// Created by Ilya Puchka on 20.01.16.
// Copyright © 2016 AliSoftware. All rights reserved.
//
import Foundation
///Provides some dummy Starship entities
struct DummyStarshipProvider : StarshipProviderAPI {
var pilotName: String
func fetchIDs(completion: ([Int]) -> Void) {
let nbShips = pilotName.characters.count
completion(Array(0..<nbShips))
}
<<<<<<< HEAD
func fetch(id: Int, completion: Starship? -> Void) {
=======
func fetch(id: Int, completion: (Starship?) -> Void) {
>>>>>>> feature/swift3
completion(dummyStarship(idx: id))
}
private func dummyStarship(idx: Int) -> Starship {
return Starship(
name: "\(pilotName)'s awesome starship #\(idx)",
model: "\(pilotName)Ship",
manufacturer: "Dummy Industries",
crew: 1 + (idx%3),
passengers: 10 + (idx*7 % 40),
pilotIDs: [idx]
)
}
}
///Provides hardcoded Starship entities stored in memory
class HardCodedStarshipProvider : StarshipProviderAPI {
let starships = [
Starship(name: "First Ship", model: "AwesomeShip", manufacturer: "HardCoded Inc.", crew: 3, passengers: 20, pilotIDs: [1,2]),
Starship(name: "Second Ship", model: "AwesomeShip Express", manufacturer: "HardCoded Inc.", crew: 4, passengers: 10, pilotIDs: [1]),
Starship(name: "Third Ship", model: "AwesomeShip Cargo", manufacturer: "HardCoded Inc.", crew: 12, passengers: 150, pilotIDs: [2]),
] + Array(4..<75).map { Starship(name: "Ship #\($0)", model: "AwesomeShip Fighter", manufacturer: "HardCoded Inc.", crew: 1, passengers: 2, pilotIDs: [1]) }
func fetchIDs(completion: ([Int]) -> Void) {
completion(Array(0..<starships.count))
}
func fetch(id: Int, completion: (Starship?) -> Void) {
guard id < starships.count else {
completion(nil)
return
}
completion(starships[id])
}
}
class FakeStarshipProvider: StarshipProviderAPI {
let dummyProvider: StarshipProviderAPI
let hardCodedProvider: StarshipProviderAPI
//Constructor injection again here
init(dummyProvider: StarshipProviderAPI, hardCodedProvider: StarshipProviderAPI) {
self.dummyProvider = dummyProvider
self.hardCodedProvider = hardCodedProvider
}
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
>>>>>>> feature/swift3
hardCodedProvider.fetchIDs(completion: completion)
}
func fetch(id: Int, completion: (Starship?) -> Void) {
if id == 0 {
dummyProvider.fetch(id: id, completion: completion)
}
else {
hardCodedProvider.fetch(id: id, completion: completion)
}
}
}
@@ -9,21 +9,21 @@
import Foundation
enum NetworkResponse {
case Success(NSData, NSHTTPURLResponse)
case Success(Data, HTTPURLResponse)
case Error(NSError)
func unwrap() throws -> (NSData, NSHTTPURLResponse) {
func unwrap() throws -> (Data, HTTPURLResponse) {
switch self {
case Success(let data, let response):
case .Success(let data, let response):
return (data, response)
case Error(let error):
case .Error(let error):
throw error
}
}
func json<T>() throws -> T {
let (data, _) = try self.unwrap()
let obj = try NSJSONSerialization.JSONObjectWithData(data, options: [])
let obj = try JSONSerialization.jsonObject(with: data, options: [])
guard let json = obj as? T else {
throw SWAPIError.InvalidJSON
}
@@ -32,5 +32,5 @@ enum NetworkResponse {
}
protocol NetworkLayer {
func request(path: String, completion: NetworkResponse -> Void)
func request(path: String, completion: @escaping (NetworkResponse) -> Void)
}
@@ -0,0 +1,40 @@
//
// NetworkLayer.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
enum NetworkResponse {
case Success(Data, HTTPURLResponse)
case Error(NSError)
func unwrap() throws -> (Data, HTTPURLResponse) {
switch self {
case Success(let data, let response):
return (data, response)
case Error(let error):
throw error
}
}
func json<T>() throws -> T {
let (data, _) = try self.unwrap()
<<<<<<< HEAD
let obj = try NSJSONSerialization.jsonObject(with: data, options: [])
=======
let obj = try JSONSerialization.jsonObject(with: data, options: [])
>>>>>>> feature/swift3
guard let json = obj as? T else {
throw SWAPIError.InvalidJSON
}
return json
}
}
protocol NetworkLayer {
func request(path: String, completion: (NetworkResponse) -> Void)
}
@@ -9,6 +9,6 @@
import Foundation
protocol PersonProviderAPI {
func fetchIDs(completion: [Int] -> Void)
func fetch(id: Int, completion: Person? -> Void)
func fetchIDs(completion: @escaping ([Int]) -> Void)
func fetch(id: Int, completion: @escaping (Person?) -> Void)
}
@@ -9,7 +9,7 @@
import Foundation
import Dip
enum SWAPIError: ErrorType {
enum SWAPIError: Error {
case InvalidJSON
}
@@ -20,8 +20,8 @@ struct SWAPIPersonProvider : PersonProviderAPI {
self.ws = webService
}
func fetchIDs(completion: [Int] -> Void) {
ws.request("people") { response in
func fetchIDs(completion: @escaping ([Int]) -> Void) {
ws.request(path: "people") { response in
do {
let dict = try response.json() as NSDictionary
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
@@ -38,14 +38,14 @@ struct SWAPIPersonProvider : PersonProviderAPI {
}
}
func fetch(id: Int, completion: Person? -> Void) {
ws.request("people/\(id)") { response in
func fetch(id: Int, completion: @escaping (Person?) -> Void) {
ws.request(path: "people/\(id)") { response in
do {
let json = try response.json() as NSDictionary
guard
let name = json["name"] as? String,
let heightStr = json["height"] as? String, height = Int(heightStr),
let massStr = json["mass"] as? String, mass = Int(massStr),
let heightStr = json["height"] as? String, let height = Int(heightStr),
let massStr = json["mass"] as? String, let mass = Int(massStr),
let hairColor = json["hair_color"] as? String,
let eyeColor = json["eye_color"] as? String,
let gender = json["gender"] as? String,
@@ -0,0 +1,81 @@
//
// SWAPIPersonProvider.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
///Provides Person entitis fetching them with web service
struct SWAPIPersonProvider : PersonProviderAPI {
let ws: NetworkLayer
//Here we inject dependency using _constructor injection_ pattern.
//The alternative way is a _property injection_
//but it should be used only for optional dependencies
//where there is a good local default implementation
init(webService: NetworkLayer) {
self.ws = webService
}
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
>>>>>>> feature/swift3
ws.request(path: "people") { response in
do {
let dict = try response.json() as NSDictionary
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
// Extract URLs (flatten to ignore invalid ones)
let urlStrings = results.flatMap({ $0["url"] as? String })
let ids = urlStrings.flatMap(idFromURLString)
completion(ids)
}
catch {
completion([])
}
}
}
<<<<<<< HEAD
func fetch(id: Int, completion: Person? -> Void) {
=======
func fetch(id: Int, completion: (Person?) -> Void) {
>>>>>>> feature/swift3
ws.request(path: "people/\(id)") { response in
do {
let json = try response.json() as NSDictionary
guard
let name = json["name"] as? String,
let heightStr = json["height"] as? String, height = Int(heightStr),
let massStr = json["mass"] as? String, mass = Int(massStr),
let hairColor = json["hair_color"] as? String,
let eyeColor = json["eye_color"] as? String,
let gender = json["gender"] as? String,
let starshipURLStrings = json["starships"] as? [String]
else {
throw SWAPIError.InvalidJSON
}
let person = Person(
name: name,
height: height,
mass: mass,
hairColor: hairColor,
eyeColor: eyeColor,
gender: Gender(rawValue: gender),
starshipIDs: starshipURLStrings.flatMap(idFromURLString)
)
completion(person)
}
catch {
completion(nil)
}
}
}
}
@@ -20,8 +20,8 @@ struct SWAPIStarshipProvider : StarshipProviderAPI {
self.ws = webService
}
func fetchIDs(completion: [Int] -> Void) {
ws.request("starships") { response in
func fetchIDs(completion: @escaping ([Int]) -> Void) {
ws.request(path: "starships") { response in
do {
let dict = try response.json() as NSDictionary
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
@@ -38,16 +38,16 @@ struct SWAPIStarshipProvider : StarshipProviderAPI {
}
}
func fetch(id: Int, completion: Starship? -> Void) {
ws.request("starships/\(id)") { response in
func fetch(id: Int, completion: @escaping (Starship?) -> Void) {
ws.request(path: "starships/\(id)") { response in
do {
let json = try response.json() as NSDictionary
guard
let name = json["name"] as? String,
let model = json["model"] as? String,
let manufacturer = json["manufacturer"] as? String,
let crewStr = json["crew"] as? String, crew = Int(crewStr),
let passengersStr = json["passengers"] as? String, passengers = Int(passengersStr),
let crewStr = json["crew"] as? String, let crew = Int(crewStr),
let passengersStr = json["passengers"] as? String, let passengers = Int(passengersStr),
let pilotIDStrings = json["pilots"] as? [String]
else {
throw SWAPIError.InvalidJSON
@@ -0,0 +1,79 @@
//
// SWAPIStarshipProvider.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
///Provides Starship entities fetching them using web service
struct SWAPIStarshipProvider : StarshipProviderAPI {
let ws: NetworkLayer
//Here we inject dependency using _constructor injection_ pattern.
//The alternative way is a _property injection_
//but it should be used only for optional dependencies
//where there is a good local default implementation
init(webService: NetworkLayer) {
self.ws = webService
}
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
>>>>>>> feature/swift3
ws.request(path: "starships") { response in
do {
let dict = try response.json() as NSDictionary
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
// Extract URLs (flatten to ignore invalid ones)
let urlStrings = results.flatMap({ $0["url"] as? String })
let ids = urlStrings.flatMap(idFromURLString)
completion(ids)
}
catch {
completion([])
}
}
}
<<<<<<< HEAD
func fetch(id: Int, completion: Starship? -> Void) {
=======
func fetch(id: Int, completion: (Starship?) -> Void) {
>>>>>>> feature/swift3
ws.request(path: "starships/\(id)") { response in
do {
let json = try response.json() as NSDictionary
guard
let name = json["name"] as? String,
let model = json["model"] as? String,
let manufacturer = json["manufacturer"] as? String,
let crewStr = json["crew"] as? String, crew = Int(crewStr),
let passengersStr = json["passengers"] as? String, passengers = Int(passengersStr),
let pilotIDStrings = json["pilots"] as? [String]
else {
throw SWAPIError.InvalidJSON
}
let ship = Starship(
name: name,
model: model,
manufacturer: manufacturer,
crew: crew,
passengers: passengers,
pilotIDs: pilotIDStrings.flatMap(idFromURLString)
)
completion(ship)
}
catch {
completion(nil)
}
}
}
}
@@ -9,6 +9,6 @@
import Foundation
protocol StarshipProviderAPI {
func fetchIDs(completion: [Int] -> Void)
func fetch(id: Int, completion: Starship? -> Void)
func fetchIDs(completion: @escaping ([Int]) -> Void)
func fetch(id: Int, completion: @escaping (Starship?) -> Void)
}
@@ -10,33 +10,33 @@ import Foundation
///NetworkLayer implementation on top of NSURLSession
struct URLSessionNetworkLayer : NetworkLayer {
let baseURL: NSURL
let session: NSURLSession
let responseQueue: dispatch_queue_t
let baseURL: URL
let session: URLSession
let responseQueue: DispatchQueue
init?(baseURL: String, session: NSURLSession = .sharedSession(), responseQueue: dispatch_queue_t = dispatch_get_main_queue()) {
guard let url = NSURL(string: baseURL) else { return nil }
init?(baseURL: String, session: URLSession = URLSession.shared, responseQueue: DispatchQueue = DispatchQueue.main) {
guard let url = URL(string: baseURL) else { return nil }
self.init(baseURL: url, session: session)
}
init(baseURL: NSURL, session: NSURLSession = .sharedSession(), responseQueue: dispatch_queue_t = dispatch_get_main_queue()) {
init(baseURL: URL, session: URLSession = URLSession.shared, responseQueue: DispatchQueue = DispatchQueue.main) {
self.baseURL = baseURL
self.session = session
self.responseQueue = responseQueue
}
func request(path: String, completion: NetworkResponse -> Void) {
let url = self.baseURL.URLByAppendingPathComponent(path)
let task = session.dataTaskWithURL(url) { data, response, error in
if let data = data, let response = response as? NSHTTPURLResponse {
dispatch_async(self.responseQueue) {
func request(path: String, completion: @escaping (NetworkResponse) -> Void) {
let url = self.baseURL.appendingPathComponent(path)
let task = session.dataTask(with: url) { data, response, error in
if let data = data, let response = response as? HTTPURLResponse {
self.responseQueue.async() {
completion(NetworkResponse.Success(data, response))
}
}
else {
let err = error ?? NSError(domain: NSURLErrorDomain, code: NSURLError.Unknown.rawValue, userInfo: nil)
dispatch_async(self.responseQueue) {
completion(NetworkResponse.Error(err))
let err = error ?? NSError(domain: NSURLErrorDomain, code: URLError.unknown.rawValue, userInfo: nil)
self.responseQueue.async() {
completion(NetworkResponse.Error(err as NSError))
}
}
}
@@ -0,0 +1,66 @@
//
// URLSessionNetworkLayer.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
///NetworkLayer implementation on top of NSURLSession
struct URLSessionNetworkLayer : NetworkLayer {
let baseURL: URL
let session: URLSession
let responseQueue: DispatchQueue
<<<<<<< HEAD
init?(baseURL: String, session: NSURLSession = NSURLSession.shared(), responseQueue: dispatch_queue_t = dispatch_get_main_queue()) {
guard let url = NSURL(string: baseURL) else { return nil }
self.init(baseURL: url, session: session)
}
init(baseURL: NSURL, session: NSURLSession = .shared(), responseQueue: dispatch_queue_t = dispatch_get_main_queue()) {
=======
init?(baseURL: String, session: URLSession = .shared(), responseQueue: DispatchQueue = DispatchQueue.main) {
guard let url = URL(string: baseURL) else { return nil }
self.init(baseURL: url, session: session)
}
init(baseURL: URL, session: URLSession = .shared(), responseQueue: DispatchQueue = DispatchQueue.main) {
>>>>>>> feature/swift3
self.baseURL = baseURL
self.session = session
self.responseQueue = responseQueue
}
<<<<<<< HEAD
func request(path: String, completion: NetworkResponse -> Void) {
let url = self.baseURL.appendingPathComponent(path)
let task = session.dataTask(with: url) { data, response, error in
if let data = data, let response = response as? NSHTTPURLResponse {
dispatch_async(self.responseQueue) {
=======
func request(path: String, completion: (NetworkResponse) -> Void) {
guard let url = try? self.baseURL.appendingPathComponent(path) else { return }
let task = session.dataTask(with: url) { data, response, error in
if let data = data, let response = response as? HTTPURLResponse {
self.responseQueue.async() {
>>>>>>> feature/swift3
completion(NetworkResponse.Success(data, response))
}
}
else {
let err = error ?? NSError(domain: NSURLErrorDomain, code: NSURLError.unknown.rawValue, userInfo: nil)
<<<<<<< HEAD
dispatch_async(self.responseQueue) {
=======
self.responseQueue.async() {
>>>>>>> feature/swift3
completion(NetworkResponse.Error(err))
}
}
}
task.resume()
}
}
@@ -21,7 +21,7 @@ extension StoryboardScene where Self.RawValue == String {
}
func viewController() -> UIViewController {
return Self.storyboard().instantiateViewControllerWithIdentifier(self.rawValue)
return Self.storyboard().instantiateViewController(withIdentifier: self.rawValue)
}
static func viewController(identifier: Self) -> UIViewController {
return identifier.viewController()
@@ -14,8 +14,8 @@ protocol FetchableTrait: class {
var batchRequestID: Int { get set }
var tableView: UITableView! { get }
func fetchIDs(completion: [Int] -> Void)
func fetchOne(id: Int, completion: ObjectType? -> Void)
func fetchIDs(completion: @escaping ([Int]) -> Void)
func fetchOne(id: Int, completion: @escaping (ObjectType?) -> Void)
var fetchProgress: (current: Int, total: Int?) { get set }
}
@@ -27,10 +27,10 @@ extension FetchableTrait {
objects?.removeAll()
fetchProgress = (0,objectIDs.count)
for objectID in objectIDs {
fetchOne(objectID) { (object: ObjectType?) in
fetchOne(id: objectID) { (object: ObjectType?) in
// Exit if we failed to retrive an object for this ID, or if the request
// should be ignored because a new batch request has been started since
guard let object = object where batch == self.batchRequestID else { return }
guard let object = object, batch == self.batchRequestID else { return }
if self.objects == nil { self.objects = [] }
self.objects?.append(object)
@@ -46,7 +46,7 @@ extension FetchableTrait {
fetchProgress = (0, nil)
fetchIDs() { objectIDs in
guard batch == self.batchRequestID else { return }
self.loadObjects(objectIDs)
self.loadObjects(objectIDs: objectIDs)
}
}
@@ -63,8 +63,8 @@ extension FetchableTrait {
}
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
label.text = text
label.textColor = .grayColor()
label.font = .systemFontOfSize(12)
label.textColor = .gray
label.font = UIFont.systemFont(ofSize: 12)
label.sizeToFit()
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: label)
}
@@ -14,45 +14,46 @@ class PersonListViewController: UITableViewController, FetchableTrait {
var personProvider: PersonProviderAPI!
var starshipProvider: StarshipProviderAPI!
func fetchIDs(completion: [Int] -> Void) {
return personProvider.fetchIDs(completion)
func fetchIDs(completion: @escaping ([Int]) -> Void) {
return personProvider.fetchIDs(completion: completion)
}
func fetchOne(personID: Int, completion: Person? -> Void) {
return personProvider.fetch(personID, completion: completion)
func fetchOne(id personID: Int, completion: @escaping (Person?) -> Void) {
return personProvider.fetch(id: personID, completion: completion)
}
var fetchProgress: (current: Int, total: Int?) = (0, nil) {
didSet {
displayProgressInNavBar(self.navigationItem)
displayProgressInNavBar(navigationItem: self.navigationItem)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard
let id = segue.identifier, segueID = UIStoryboard.Segue.Main(rawValue: id)
where segueID == .StarshipsSegue,
let id = segue.identifier,
let segueID = UIStoryboard.Segue.Main(rawValue: id),
segueID == .StarshipsSegue,
let indexPath = self.tableView.indexPathForSelectedRow,
let destVC = segue.destinationViewController as? StarshipListViewController,
let destVC = segue.destination as? StarshipListViewController,
let person = self.objects?[indexPath.row]
else {
fatalError()
}
destVC.starshipProvider = starshipProvider
destVC.loadObjects(person.starshipIDs)
destVC.loadObjects(objectIDs: person.starshipIDs)
}
}
extension PersonListViewController {
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = PersonCell.dequeueFromTableView(tableView, forIndexPath: indexPath)
cell.fillWithObject(object)
cell.fillWithObject(object: object)
return cell
}
}
@@ -0,0 +1,73 @@
//
// PersonListViewController.swift
// Dip
//
// Created by Olivier Halligon on 09/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
class PersonListViewController: UITableViewController, FetchableTrait {
var objects: [Person]?
var batchRequestID = 0
var personProvider: PersonProviderAPI!
var starshipProvider: StarshipProviderAPI!
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
return personProvider.fetchIDs(completion: completion)
}
func fetchOne(id personID: Int, completion: Person? -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
return personProvider.fetchIDs(completion: completion)
}
func fetchOne(id personID: Int, completion: (Person?) -> Void) {
>>>>>>> feature/swift3
return personProvider.fetch(id: personID, completion: completion)
}
var fetchProgress: (current: Int, total: Int?) = (0, nil) {
didSet {
displayProgressInNavBar(navigationItem: self.navigationItem)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
guard
let id = segue.identifier, segueID = UIStoryboard.Segue.Main(rawValue: id)
where segueID == .StarshipsSegue,
let indexPath = self.tableView.indexPathForSelectedRow,
let destVC = segue.destinationViewController as? StarshipListViewController,
let person = self.objects?[indexPath.row]
else {
fatalError()
}
destVC.starshipProvider = starshipProvider
destVC.loadObjects(objectIDs: person.starshipIDs)
}
}
extension PersonListViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}
<<<<<<< HEAD
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: NSIndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = PersonCell.dequeueFromTableView(tableView: tableView, forIndexPath: indexPath)
=======
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = PersonCell.dequeueFromTableView(tableView, forIndexPath: indexPath)
>>>>>>> feature/swift3
cell.fillWithObject(object: object)
return cell
}
}
@@ -16,44 +16,45 @@ class StarshipListViewController : UITableViewController, FetchableTrait {
var starshipProvider: StarshipProviderAPI!
var personProvider: PersonProviderAPI!
func fetchIDs(completion: [Int] -> Void) {
starshipProvider.fetchIDs(completion)
func fetchIDs(completion: @escaping ([Int]) -> Void) {
starshipProvider.fetchIDs(completion: completion)
}
func fetchOne(shipID:Int, completion: Starship? -> Void) {
starshipProvider.fetch(shipID, completion: completion)
func fetchOne(id shipID:Int, completion: @escaping (Starship?) -> Void) {
starshipProvider.fetch(id: shipID, completion: completion)
}
var fetchProgress: (current: Int, total: Int?) = (0, nil) {
didSet {
displayProgressInNavBar(self.navigationItem)
displayProgressInNavBar(navigationItem: self.navigationItem)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard
let id = segue.identifier, segueID = UIStoryboard.Segue.Main(rawValue: id)
where segueID == .PilotsSegue,
let id = segue.identifier,
let segueID = UIStoryboard.Segue.Main(rawValue: id),
segueID == .PilotsSegue,
let indexPath = self.tableView.indexPathForSelectedRow,
let destVC = segue.destinationViewController as? PersonListViewController,
let destVC = segue.destination as? PersonListViewController,
let starship = self.objects?[indexPath.row]
else {
fatalError()
}
destVC.personProvider = personProvider
destVC.loadObjects(starship.pilotIDs)
destVC.loadObjects(objectIDs: starship.pilotIDs)
}
}
extension StarshipListViewController {
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = StarshipCell.dequeueFromTableView(tableView, forIndexPath: indexPath)
cell.fillWithObject(object)
cell.fillWithObject(object: object)
return cell
}
}
@@ -0,0 +1,72 @@
//
// StarshipListViewController.swift
// Dip
//
// Created by Olivier Halligon on 09/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
import Dip
class StarshipListViewController : UITableViewController, FetchableTrait {
var objects: [Starship]?
var batchRequestID = 0
var starshipProvider: StarshipProviderAPI!
var personProvider: PersonProviderAPI!
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
starshipProvider.fetchIDs(completion: completion)
}
func fetchOne(id shipID:Int, completion: Starship? -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
starshipProvider.fetchIDs(completion: completion)
}
func fetchOne(id shipID:Int, completion: (Starship?) -> Void) {
>>>>>>> feature/swift3
starshipProvider.fetch(id: shipID, completion: completion)
}
var fetchProgress: (current: Int, total: Int?) = (0, nil) {
didSet {
displayProgressInNavBar(navigationItem: self.navigationItem)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
guard
let id = segue.identifier, segueID = UIStoryboard.Segue.Main(rawValue: id)
where segueID == .PilotsSegue,
let indexPath = self.tableView.indexPathForSelectedRow,
let destVC = segue.destinationViewController as? PersonListViewController,
let starship = self.objects?[indexPath.row]
else {
fatalError()
}
destVC.personProvider = personProvider
destVC.loadObjects(objectIDs: starship.pilotIDs)
}
}
extension StarshipListViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}
<<<<<<< HEAD
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: NSIndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = StarshipCell.dequeueFromTableView(tableView: tableView, forIndexPath: indexPath)
=======
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = StarshipCell.dequeueFromTableView(tableView, forIndexPath: indexPath)
>>>>>>> feature/swift3
cell.fillWithObject(object: object)
return cell
}
}
+8 -8
View File
@@ -14,24 +14,24 @@ var wsDependencies = DependencyContainer()
// MARK: - Mock object used for tests
struct NetworkMock : NetworkLayer {
let fakeData: NSData?
let fakeData: Data?
init(json: AnyObject) {
init(json: Any) {
do {
fakeData = try NSJSONSerialization.dataWithJSONObject(json, options: [])
fakeData = try JSONSerialization.data(withJSONObject: json, options: [])
} catch {
fakeData = nil
}
}
func request(path: String, completion: NetworkResponse -> Void) {
let fakeURL = NSURL(string: "stub://")!.URLByAppendingPathComponent(path)
func request(path: String, completion: @escaping (NetworkResponse) -> Void) {
let fakeURL = NSURL(string: "http://stub")?.appendingPathComponent(path)
if let data = fakeData {
let response = NSHTTPURLResponse(URL: fakeURL, statusCode: 200, HTTPVersion: "1.1", headerFields:nil)!
let response = HTTPURLResponse(url: fakeURL!, statusCode: 200, httpVersion: "1.1", headerFields:nil)!
completion(.Success(data, response))
} else {
let response = NSHTTPURLResponse(URL: fakeURL, statusCode: 204, HTTPVersion: "1.1", headerFields:nil)!
completion(.Success(NSData(), response))
let response = HTTPURLResponse(url: fakeURL!, statusCode: 204, httpVersion: "1.1", headerFields:nil)!
completion(.Success(Data(), response))
}
}
}
+52
View File
@@ -0,0 +1,52 @@
//
// NetworkMock.swift
// Dip
//
// Created by Olivier Halligon on 11/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
import Dip
var wsDependencies = DependencyContainer()
// MARK: - Mock object used for tests
struct NetworkMock : NetworkLayer {
let fakeData: Data?
init(json: AnyObject) {
do {
<<<<<<< HEAD
fakeData = try NSJSONSerialization.data(withJSONObject: json, options: [])
=======
fakeData = try JSONSerialization.data(withJSONObject: json, options: [])
>>>>>>> feature/swift3
} catch {
fakeData = nil
}
}
<<<<<<< HEAD
func request(path: String, completion: NetworkResponse -> Void) {
let fakeURL = NSURL(string: "stub://")!.appendingPathComponent(path)
if let data = fakeData {
let response = NSHTTPURLResponse(url: fakeURL, statusCode: 200, httpVersion: "1.1", headerFields:nil)!
completion(.Success(data, response))
} else {
let response = NSHTTPURLResponse(url: fakeURL, statusCode: 204, httpVersion: "1.1", headerFields:nil)!
completion(.Success(NSData(), response))
=======
func request(path: String, completion: (NetworkResponse) -> Void) {
let fakeURL = try! URL(string: "stub://")!.appendingPathComponent(path)
if let data = fakeData {
let response = HTTPURLResponse(url: fakeURL, statusCode: 200, httpVersion: "1.1", headerFields:nil)!
completion(.Success(data, response))
} else {
let response = HTTPURLResponse(url: fakeURL, statusCode: 204, httpVersion: "1.1", headerFields:nil)!
completion(.Success(Data(), response))
>>>>>>> feature/swift3
}
}
}
@@ -10,10 +10,10 @@ import XCTest
import Dip
class SWAPIPersonProviderTests: XCTestCase {
let fakePerson1 = ["name": "John Doe", "mass": "72", "height": "172", "eye_color": "brown", "hair_color": "black", "gender": "male",
"starships": ["stub://starship/7/", "stub://starship/15"], "url": "stub://people/1"]
let fakePerson2 = ["name": "Jane Doe", "mass": "63", "height": "167", "eye_color": "blue", "hair_color": "red", "gender": "female",
"starships": ["stub://starship/11/"], "url": "stub://people/12"]
let fakePerson1: [String : Any] = ["name": "John Doe", "mass": "72", "height": "172", "eye_color": "brown", "hair_color": "black", "gender": "male",
"starships": ["http://starship/7/", "http://starship/15"], "url": "http://people/1"]
let fakePerson2: [String: Any] = ["name": "Jane Doe", "mass": "63", "height": "167", "eye_color": "blue", "hair_color": "red", "gender": "female",
"starships": ["http://starship/11/"], "url": "http://people/12"]
override func setUp() {
super.setUp()
@@ -23,7 +23,7 @@ class SWAPIPersonProviderTests: XCTestCase {
func testFetchPersonIDs() {
let mock = NetworkMock(json: ["results": [fakePerson1, fakePerson2]])
wsDependencies.register(.Singleton) { mock as NetworkLayer }
wsDependencies.register(.singleton) { mock as NetworkLayer }
let provider = SWAPIPersonProvider(webService: try! wsDependencies.resolve())
provider.fetchIDs { personIDs in
@@ -37,10 +37,10 @@ class SWAPIPersonProviderTests: XCTestCase {
func testFetchOnePerson() {
let mock = NetworkMock(json: fakePerson1)
wsDependencies.register(.Singleton) { mock as NetworkLayer }
wsDependencies.register(.singleton) { mock as NetworkLayer }
let provider = SWAPIPersonProvider(webService: try! wsDependencies.resolve())
provider.fetch(1) { person in
provider.fetch(id: 1) { person in
XCTAssertNotNil(person)
XCTAssertEqual(person?.name, "John Doe")
XCTAssertEqual(person?.mass, 72)
@@ -57,10 +57,10 @@ class SWAPIPersonProviderTests: XCTestCase {
func testFetchInvalidPerson() {
let json = ["error":"whoops"]
let mock = NetworkMock(json: json)
wsDependencies.register(.Singleton) { mock as NetworkLayer }
wsDependencies.register(.singleton) { mock as NetworkLayer }
let provider = SWAPIPersonProvider(webService: try! wsDependencies.resolve())
provider.fetch(12) { person in
provider.fetch(id: 12) { person in
XCTAssertNil(person)
}
}
@@ -10,10 +10,10 @@ import XCTest
import Dip
class SWAPIStarshipProviderTests: XCTestCase {
let fakeShip1 = ["name": "Falcon", "model": "Fighter", "manufacturer": "Fake Industries", "crew": "7", "passengers": "15",
"pilots": ["stub://people/1/", "stub://people/9"], "url": "stub://starship/4"]
let fakeShip2 = ["name": "Voyager", "model": "Cargo", "manufacturer": "Fake Industries", "crew": "18", "passengers": "150",
"pilots": ["stub://people/2/", "stub://people/3"], "url": "stub://starship/31"]
let fakeShip1: [String: Any] = ["name": "Falcon", "model": "Fighter", "manufacturer": "Fake Industries", "crew": "7", "passengers": "15",
"pilots": ["http://people/1/", "http://people/9"], "url": "http://starship/4"]
let fakeShip2: [String: Any] = ["name": "Voyager", "model": "Cargo", "manufacturer": "Fake Industries", "crew": "18", "passengers": "150",
"pilots": ["http://people/2/", "http://people/3"], "url": "http://starship/31"]
override func setUp() {
super.setUp()
@@ -23,7 +23,7 @@ class SWAPIStarshipProviderTests: XCTestCase {
func testFetchStarshipIDs() {
let mock = NetworkMock(json: ["results": [fakeShip1, fakeShip2]])
wsDependencies.register(.Singleton) { mock as NetworkLayer }
wsDependencies.register(.singleton) { mock as NetworkLayer }
let provider = SWAPIStarshipProvider(webService: try! wsDependencies.resolve())
provider.fetchIDs { shipIDs in
@@ -38,10 +38,10 @@ class SWAPIStarshipProviderTests: XCTestCase {
func testFetchOneStarship() {
let mock = NetworkMock(json: fakeShip1)
wsDependencies.register(.Singleton) { mock as NetworkLayer }
wsDependencies.register(.singleton) { mock as NetworkLayer }
let provider = SWAPIStarshipProvider(webService: try! wsDependencies.resolve())
provider.fetch(1) { starship in
provider.fetch(id: 1) { starship in
XCTAssertNotNil(starship)
XCTAssertEqual(starship?.name, "Falcon")
XCTAssertEqual(starship?.model, "Fighter")
@@ -57,10 +57,10 @@ class SWAPIStarshipProviderTests: XCTestCase {
func testFetchInvalidStarship() {
let json = ["error":"whoops"]
let mock = NetworkMock(json: json)
wsDependencies.register(.Singleton) { mock as NetworkLayer }
wsDependencies.register(.singleton) { mock as NetworkLayer }
let provider = SWAPIStarshipProvider(webService: try! wsDependencies.resolve())
provider.fetch(12) { starship in
provider.fetch(id: 12) { starship in
XCTAssertNil(starship)
}
}
+40 -34
View File
@@ -27,15 +27,28 @@ extension DependencyContainer {
/**
Resolves properties of passed object wrapped with `Injected<T>` or `InjectedWeak<T>`
*/
func autoInjectProperties(instance: Any) throws {
try Mirror(reflecting: instance).children.forEach(resolveChild)
func autoInjectProperties(_ instance: Any) throws {
let mirror = Mirror(reflecting: instance)
//mirror only contains class own properties
//so we need to walk through super class mirrors
//to resolve super class auto-injected properties
var superClassMirror = mirror.superclassMirror
while superClassMirror != nil {
try superClassMirror?.children.forEach(resolveChild)
superClassMirror = superClassMirror?.superclassMirror
}
try mirror.children.forEach(resolveChild)
}
private func resolveChild(child: Mirror.Child) throws {
//HOTFIX for https://bugs.swift.org/browse/SR-2282
guard !String(describing: type(of: child.value)).hasPrefix("ImplicitlyUnwrappedOptional") else { return }
guard let injectedPropertyBox = child.value as? AutoInjectedPropertyBox else { return }
let contextKey = DefinitionKey(protocolType: injectedPropertyBox.dynamicType.wrappedType, argumentsType: Void.self, associatedTag: context.tag)
try inContext(contextKey, injectedInProperty: child.label, logErrors: false) {
let contextKey = DefinitionKey(type: type(of: injectedPropertyBox).wrappedType, typeOfArguments: Void.self, tag: context.tag)
try inContext(contextKey, injectedInType: context?.resolvingType, injectedInProperty: child.label, logErrors: false) {
try injectedPropertyBox.resolve(self)
}
}
@@ -76,7 +89,7 @@ public protocol AutoInjectedPropertyBox: class {
- note: This method is not intended to be called manually, `DependencyContainer` will call it by itself.
*/
func resolve(container: DependencyContainer) throws
func resolve(_ container: DependencyContainer) throws
}
/**
@@ -121,26 +134,26 @@ public final class Injected<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox
- didInject: block that will be called when concrete instance is injected in this property.
Similar to `didSet` property observer. Default value does nothing.
*/
public convenience init(required: Bool = true, didInject: T -> () = { _ in }) {
public convenience init(required: Bool = true, didInject: @escaping (T) -> () = { _ in }) {
self.init(value: nil, required: required, tag: nil, overrideTag: false, didInject: didInject)
}
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: T -> () = { _ in }) {
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: @escaping (T) -> () = { _ in }) {
self.init(value: nil, required: required, tag: tag, overrideTag: true, didInject: didInject)
}
private init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: T -> ()) {
private init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> ()) {
self.value = value
super.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
}
public func resolve(container: DependencyContainer) throws {
public func resolve(_ container: DependencyContainer) throws {
let resolved: T? = try super.resolve(container)
value = resolved
}
/// Returns a new wrapper with provided value.
public func setValue(value: T?) -> Injected {
public func setValue(_ value: T?) -> Injected {
guard (required && value != nil) || !required else {
fatalError("Can not set required property to nil.")
}
@@ -191,7 +204,7 @@ public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropert
return T.self
}
private weak var _value: AnyObject? = nil {
private var valueBox: WeakBox<T>? = nil {
didSet {
if let value = value { didInject(value) }
}
@@ -199,7 +212,7 @@ public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropert
///Wrapped value.
public var value: T? {
return _value as? T
return valueBox?.value
}
/**
@@ -213,34 +226,27 @@ public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropert
- didInject: block that will be called when concrete instance is injected in this property.
Similar to `didSet` property observer. Default value does nothing.
*/
public convenience init(required: Bool = true, didInject: T -> () = { _ in }) {
public convenience init(required: Bool = true, didInject: @escaping (T) -> () = { _ in }) {
self.init(value: nil, required: required, tag: nil, overrideTag: false, didInject: didInject)
}
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: T -> () = { _ in }) {
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: @escaping (T) -> () = { _ in }) {
self.init(value: nil, required: required, tag: tag, overrideTag: true, didInject: didInject)
}
private init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: T -> ()) {
self._value = value as? AnyObject
private init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> ()) {
self.valueBox = value.map(WeakBox.init)
super.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
}
public func resolve(container: DependencyContainer) throws {
public func resolve(_ container: DependencyContainer) throws {
let resolved: T? = try super.resolve(container)
if required && !(resolved is AnyObject) {
fatalError("\(T.self) can not be casted to AnyObject. InjectedWeak wrapper should be used to wrap only classes.")
}
_value = resolved as? AnyObject
valueBox = resolved.map(WeakBox.init)
}
/// Returns a new wrapper with provided value.
public func setValue(value: T?) -> InjectedWeak {
let _value = value as? AnyObject
if value != nil && _value == nil {
fatalError("\(T.self) can not be casted to AnyObject. InjectedWeak wrapper should be used to wrap only classes.")
}
guard (required && _value != nil) || !required else {
public func setValue(_ value: T?) -> InjectedWeak {
guard (required && value != nil) || !required else {
fatalError("Can not set required property to nil.")
}
@@ -252,26 +258,26 @@ public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropert
private class _InjectedPropertyBox<T> {
let required: Bool
let didInject: T -> ()
let didInject: (T) -> ()
let tag: DependencyContainer.Tag?
let overrideTag: Bool
init(required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: T -> () = { _ in }) {
init(required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> () = { _ in }) {
self.required = required
self.tag = tag?.dependencyTag
self.overrideTag = overrideTag
self.didInject = didInject
}
private func resolve(container: DependencyContainer) throws -> T? {
fileprivate func resolve(_ container: DependencyContainer) throws -> T? {
let tag = overrideTag ? self.tag : container.context.tag
do {
container.context.key = container.context.key.tagged(tag)
let key = DefinitionKey(protocolType: T.self, argumentsType: Void.self, associatedTag: tag?.dependencyTag)
let key = DefinitionKey(type: T.self, typeOfArguments: Void.self, tag: tag?.dependencyTag)
return try resolve(container, key: key, builder: { factory in try factory() }) as? T
}
catch {
let error = DipError.AutoInjectionFailed(label: container.context.injectedInProperty, type: container.context.resolvingType, underlyingError: error)
let error = DipError.autoInjectionFailed(label: container.context.injectedInProperty, type: container.context.resolvingType, underlyingError: error)
if required {
throw error
@@ -283,8 +289,8 @@ private class _InjectedPropertyBox<T> {
}
}
private func resolve<U>(container: DependencyContainer, key: DefinitionKey, builder: (U throws -> Any) throws -> Any) throws -> Any {
return try container.resolveKey(key, builder: { definition throws -> Any in
private func resolve<U>(_ container: DependencyContainer, key: DefinitionKey, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
return try container.resolve(key: key, builder: { definition throws -> Any in
try builder(definition.weakFactory)
})
}
+30 -102
View File
@@ -22,125 +22,53 @@
// THE SOFTWARE.
//
protocol AutoWiringDefinition: Definition {
var numberOfArguments: Int? { get }
protocol AutoWiringDefinition: DefinitionType {
var numberOfArguments: Int { get }
var autoWiringFactory: ((DependencyContainer, DependencyContainer.Tag?) throws -> Any)? { get }
}
extension AutoWiringDefinition {
func supportsAutoWiring() -> Bool {
return autoWiringFactory != nil && numberOfArguments > 0
}
}
extension DependencyContainer {
/// Tries to resolve instance using auto-wire factories
func autowire<T>(key: DefinitionKey) throws -> T {
let shouldLogErrors = context.logErrors
defer { context.logErrors = shouldLogErrors }
context.logErrors = false
guard key.argumentsType == Void.self else {
throw DipError.DefinitionNotFound(key: key)
/// Tries to resolve instance using auto-wiring
func autowire<T>(_ key: DefinitionKey) throws -> T {
guard key.typeOfArguments == Void.self else {
throw DipError.definitionNotFound(key: key)
}
let tag = key.associatedTag
let type = key.protocolType
let resolved: Any?
let autoWiringKey = try autoWiringDefinition(byKey: key).key
do {
let definitions = autoWiringDefinitions(type, tag: tag)
resolved = try resolve(enumerating: definitions) { try resolveKey($0, tag: tag, type: type) }
let key = autoWiringKey.tagged(key.tag ?? context.tag)
return try resolve(key: key) { definition in
try definition.autoWiringFactory!(self, key.tag) as! T
}
}
catch {
throw DipError.AutoWiringFailed(type: type, underlyingError: error)
}
if let resolved = resolved as? T {
return resolved
}
else {
throw DipError.DefinitionNotFound(key: key)
throw DipError.autoWiringFailed(type: key.type, underlyingError: error)
}
}
private func autoWiringDefinitions(type: Any.Type, tag: DependencyContainer.Tag?) -> [KeyDefinitionPair] {
private func autoWiringDefinition(byKey key: DefinitionKey) throws -> KeyDefinitionPair {
var definitions = self.definitions.map({ (key: $0.0, definition: $0.1) })
//filter definitions
definitions = definitions
.filter({ $0.definition.supportsAutoWiring() })
.sort({ $0.definition.numberOfArguments > $1.definition.numberOfArguments })
definitions = filter(definitions, type: type, tag: tag)
definitions = order(definitions, tag: tag)
definitions = filter(definitions, byKey: key)
definitions = definitions.sorted(by: { $0.definition.numberOfArguments > $1.definition.numberOfArguments })
return definitions
}
/// Enumerates definitions one by one until one of them succeeds, otherwise returns nil
private func resolve(enumerating keyDefinitionPairs: [KeyDefinitionPair], @noescape block: (DefinitionKey) throws -> Any?) throws -> Any? {
for (index, keyDefinitionPair) in keyDefinitionPairs.enumerate() {
//If the next definition matches current definition then they are ambigous
if let nextPair = keyDefinitionPairs[next: index], case keyDefinitionPair = nextPair {
throw DipError.AmbiguousDefinitions(
type: keyDefinitionPair.key.protocolType,
definitions: [keyDefinitionPair.definition, nextPair.definition]
)
}
if let resolved = try block(keyDefinitionPair.key) {
return resolved
}
guard definitions.count > 0 && definitions[0].definition.numberOfArguments > 0 else {
throw DipError.definitionNotFound(key: key)
}
let maximumNumberOfArguments = definitions.first?.definition.numberOfArguments
definitions = definitions.filter({ $0.definition.numberOfArguments == maximumNumberOfArguments })
definitions = order(definitions, byTag: key.tag)
//when there are several definitions with the same number of arguments but different arguments types
if definitions.count > 1 && definitions[0].key.typeOfArguments != definitions[1].key.typeOfArguments {
let error = DipError.ambiguousDefinitions(type: key.type, definitions: definitions.map({ $0.definition }))
throw DipError.autoWiringFailed(type: key.type, underlyingError: error)
} else {
return definitions[0]
}
return nil
}
private func resolveKey(key: DefinitionKey, tag: DependencyContainer.Tag?, type: Any.Type) throws -> Any {
let key = key.tagged(tag ?? context.tag)
let resolved: Any = try resolveKey(key, builder: { definition in
try definition.autoWiringFactory!(self, tag)
})
return resolved
}
}
extension CollectionType where Self.Index: Comparable {
subscript(safe index: Index) -> Generator.Element? {
guard indices ~= index else { return nil }
return self[index]
}
subscript(next index: Index) -> Generator.Element? {
return self[safe: index.advancedBy(1)]
}
}
typealias KeyDefinitionPair = (key: DefinitionKey, definition: _Definition)
/// Definitions are matched if they are registered for the same tag and thier factories accept the same number of runtime arguments.
private func ~=(lhs: KeyDefinitionPair, rhs: KeyDefinitionPair) -> Bool {
guard lhs.key.protocolType == rhs.key.protocolType else { return false }
guard lhs.key.associatedTag == rhs.key.associatedTag else { return false }
guard lhs.definition.numberOfArguments == rhs.definition.numberOfArguments else { return false }
return true
}
func filter(definitions: [KeyDefinitionPair], type: Any.Type, tag: DependencyContainer.Tag?, argumentsType: Any.Type? = nil) -> [KeyDefinitionPair] {
let definitions = definitions
.filter({ $0.key.protocolType == type || $0.definition.doesImplements(type) })
.filter({ $0.key.associatedTag == tag || $0.key.associatedTag == nil })
if let argumentsType = argumentsType {
return definitions.filter({ $0.key.argumentsType == argumentsType })
}
return definitions
}
func order(definitions: [KeyDefinitionPair], tag: DependencyContainer.Tag?) -> [KeyDefinitionPair] {
return
//first will try to use tagged definitions
definitions.filter({ $0.key.associatedTag == tag }) +
//then will use not tagged definitions
definitions.filter({ $0.key.associatedTag != tag })
}
+136 -82
View File
@@ -24,38 +24,38 @@
///A key used to store definitons in a container.
public struct DefinitionKey : Hashable, CustomStringConvertible {
public let protocolType: Any.Type
public let argumentsType: Any.Type
public private(set) var associatedTag: DependencyContainer.Tag?
init(protocolType: Any.Type, argumentsType: Any.Type, associatedTag: DependencyContainer.Tag? = nil) {
self.protocolType = protocolType
self.argumentsType = argumentsType
self.associatedTag = associatedTag
public let type: Any.Type
public let typeOfArguments: Any.Type
public private(set) var tag: DependencyContainer.Tag?
init(type: Any.Type, typeOfArguments: Any.Type, tag: DependencyContainer.Tag? = nil) {
self.type = type
self.typeOfArguments = typeOfArguments
self.tag = tag
}
public var hashValue: Int {
return "\(protocolType)-\(argumentsType)-\(associatedTag)".hashValue
return "\(type)-\(typeOfArguments)-\(tag)".hashValue
}
public var description: String {
return "type: \(protocolType), arguments: \(argumentsType), tag: \(associatedTag.desc)"
return "type: \(type), arguments: \(typeOfArguments), tag: \(tag.desc)"
}
func tagged(tag: DependencyContainer.Tag?) -> DefinitionKey {
func tagged(_ tag: DependencyContainer.Tag?) -> DefinitionKey {
var tagged = self
tagged.associatedTag = tag
tagged.tag = tag
return tagged
}
}
/// Check two definition keys on equality by comparing their `protocolType`, `factoryType` and `associatedTag` properties.
/// Check two definition keys on equality by comparing their `type`, `factoryType` and `tag` properties.
public func ==(lhs: DefinitionKey, rhs: DefinitionKey) -> Bool {
return
lhs.protocolType == rhs.protocolType &&
lhs.argumentsType == rhs.argumentsType &&
lhs.associatedTag == rhs.associatedTag
lhs.type == rhs.type &&
lhs.typeOfArguments == rhs.typeOfArguments &&
lhs.tag == rhs.tag
}
///Component scope defines a strategy used by the `DependencyContainer` to manage resolved instances life cycle.
@@ -80,7 +80,7 @@ public enum ComponentScope {
```
*/
case Prototype
case unique
/**
Instance resolved with the same definition will be reused until topmost `resolve(tag:)` method returns.
@@ -92,7 +92,7 @@ public enum ComponentScope {
**Example**:
```
container.register(.ObjectGraph) { ServiceImp() as Service }
container.register { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
@@ -106,8 +106,8 @@ public enum ComponentScope {
consumer1.service1 !== consumer2.service1 //true
```
*/
case ObjectGraph
case shared
/**
Resolved instance will be retained by the container and always reused.
Do not mix this life cycle with _singleton pattern_.
@@ -122,7 +122,7 @@ public enum ComponentScope {
**Example**:
```
container.register(.Singleton) { ServiceImp() as Service }
container.register(.singleton) { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
@@ -136,53 +136,56 @@ public enum ComponentScope {
consumer1.service1 === consumer2.service1 //true
```
*/
case Singleton
case singleton
/**
The same scope as a `Singleton`, but instance will be created when container is bootstrapped.
- seealso: `bootstrap()`
*/
case EagerSingleton
case eagerSingleton
/**
The same scope as a `Singleton`, but container stores week reference to the resolved instance.
While a strong reference to the resolved instance exists resolve will return the same instance.
After the resolved instance is deallocated next resolve will produce a new instance.
*/
case WeakSingleton
case weakSingleton
}
///Dummy protocol to store definitions for different types in collection
public protocol Definition: class { }
public protocol DefinitionType: class { }
/**
`DefinitionOf<T, F>` describes how instances of type `T` should be created when this type is resolved by the `DependencyContainer`.
`Definition<T, U>` describes how instances of type `T` should be created when this type is resolved by the `DependencyContainer`.
- `T` is the type of the instance to resolve
- `F` is the type of the factory that will create an instance of T.
- `U` is the type of runtime arguments accepted by factory that will create an instance of T.
For example `DefinitionOf<Service, (String) -> Service>` is the type of definition that will create an instance of type `Service` using factory that accepts `String` argument.
For example `Definition<Service, String>` is the type of definition that will create an instance of type `Service` using factory that accepts `String` argument.
*/
public final class DefinitionOf<T, F>: Definition {
public final class Definition<T, U>: DefinitionType {
public typealias F = (U) throws -> T
init(scope: ComponentScope, factory: F) {
init(scope: ComponentScope, factory: @escaping F) {
self.factory = factory
self.scope = scope
}
//MARK: - _Definition
weak var container: DependencyContainer?
let factory: F
let scope: ComponentScope
private(set) var weakFactory: (Any throws -> Any)!
private(set) var resolveDependenciesBlock: ((DependencyContainer, Any) throws -> ())?
fileprivate(set) var weakFactory: ((Any) throws -> Any)!
fileprivate(set) var resolveProperties: ((DependencyContainer, Any) throws -> ())?
/**
Set the block that will be used to resolve dependencies of the instance.
This block will be called before `resolve(tag:)` returns.
- parameter block: The block to use to resolve dependencies of the instance.
- parameter block: The block to resolve property dependencies of the instance.
- returns: modified definition
@@ -198,103 +201,122 @@ public final class DefinitionOf<T, F>: Definition {
container.register { ClientImp(service: try container.resolve() as Service) as Client }
container.register { ServiceImp() as Service }
.resolveDependencies { container, service in
.resolvingProperties { container, service in
service.client = try container.resolve() as Client
}
```
*/
public func resolveDependencies(block: (DependencyContainer, T) throws -> ()) -> DefinitionOf {
let oldBlock = self.resolveDependenciesBlock
self.resolveDependenciesBlock = {
try oldBlock?($0, $1 as! T)
try block($0, $1 as! T)
@discardableResult public func resolvingProperties(_ block: @escaping (DependencyContainer, T) throws -> ()) -> Definition {
if let oldBlock = self.resolveProperties {
self.resolveProperties = {
try oldBlock($0, $1 as! T)
try block($0, $1 as! T)
}
}
else {
self.resolveProperties = { try block($0, $1 as! T) }
}
return self
}
/// Calls `resolveDependencies` block if it was set.
func resolveDependenciesOf(resolvedInstance: Any, withContainer container: DependencyContainer) throws {
guard let resolvedInstance = resolvedInstance as? T else { return }
if let resolveDependenciesBlock = self.resolveDependenciesBlock {
try resolveDependenciesBlock(container, resolvedInstance)
func resolveProperties(of instance: Any, container: DependencyContainer) throws {
guard let resolvedInstance = instance as? T else { return }
if let forwardsTo = forwardsTo {
try forwardsTo.resolveProperties(of: resolvedInstance, container: container)
}
if let resolveProperties = self.resolveProperties {
try resolveProperties(container, resolvedInstance)
}
}
//MARK: - AutoWiringDefinition
private(set) var autoWiringFactory: ((DependencyContainer, DependencyContainer.Tag?) throws -> Any)?
private(set) var numberOfArguments: Int?
fileprivate(set) var autoWiringFactory: ((DependencyContainer, DependencyContainer.Tag?) throws -> Any)?
fileprivate(set) var numberOfArguments: Int = 0
//MARK: - TypeForwardingDefinition
/// Types that can be resolved using this definition.
private(set) var implementingTypes: [Any.Type] = [(T?).self, (T!).self]
fileprivate(set) var implementingTypes: [Any.Type] = [(T?).self, (T!).self]
/// Return `true` if type can be resolved using this definition
func doesImplements(type: Any.Type) -> Bool {
return implementingTypes.contains({ $0 == type })
func doesImplements(_ type: Any.Type) -> Bool {
return implementingTypes.contains(where: { $0 == type })
}
//MARK: - _TypeForwardingDefinition
/// Adds type as being able to be resolved using this definition
private func implements(type: Any.Type) {
implements([type])
fileprivate func _implements(_ type: Any.Type) {
_implements([type])
}
/// Adds types as being able to be resolved using this definition
private func implements(types: [Any.Type]) {
implementingTypes.appendContentsOf(types.filter({ !doesImplements($0) }))
fileprivate func _implements(_ types: [Any.Type]) {
implementingTypes.append(contentsOf: types.filter({ !doesImplements($0) }))
}
/// Definition to which resolution will be forwarded to
private weak var forwardsToDefinition: _TypeForwardingDefinition? {
fileprivate weak var forwardsTo: _TypeForwardingDefinition? {
didSet {
if let forwardsToDefinition = forwardsToDefinition {
implements(forwardsToDefinition.type)
implements(forwardsToDefinition.implementingTypes)
//both definitions (self and forwardsTo) can resolve
//each other types and each other implementing types
//this relationship can be used to reuse previously resolved instances
if let forwardsTo = forwardsTo {
_implements(forwardsTo.type)
_implements(forwardsTo.implementingTypes)
for definition in [forwardsToDefinition] + forwardsToDefinition.forwardsFromDefinitions {
definition.implements(type)
definition.implements(implementingTypes)
//definitions for types that can be resolved by `forwardsTo` definition
//can also be used to resolve self type and it's implementing types
//this way container properly reuses previosly resolved instances
//when there are several forwarded definitions
//see testThatItReusesInstanceResolvedByTypeForwarding)
for definition in forwardsTo.forwardsFrom {
definition._implements(type)
definition._implements(implementingTypes)
}
forwardsToDefinition.forwardsFromDefinitions.append(self)
resolveDependencies({ try forwardsToDefinition.resolveDependenciesOf($1, withContainer: $0) })
//forwardsTo can be used to resolve self type and it's implementing types
forwardsTo._implements(type)
forwardsTo._implements(implementingTypes)
forwardsTo.forwardsFrom.append(self)
}
}
}
/// Definitions that will forward resolution to this definition
private var forwardsFromDefinitions: [_TypeForwardingDefinition] = []
fileprivate var forwardsFrom: [_TypeForwardingDefinition] = []
}
//MARK: - _Definition
protocol _Definition: Definition, AutoWiringDefinition, TypeForwardingDefinition {
protocol _Definition: DefinitionType, AutoWiringDefinition, TypeForwardingDefinition {
var type: Any.Type { get }
var scope: ComponentScope { get }
var weakFactory: (Any throws -> Any)! { get }
func resolveDependenciesOf(resolvedInstance: Any, withContainer container: DependencyContainer) throws
var weakFactory: ((Any) throws -> Any)! { get }
func resolveProperties(of instance: Any, container: DependencyContainer) throws
var container: DependencyContainer? { get set }
}
//MARK: - Type Forwarding
private protocol _TypeForwardingDefinition: TypeForwardingDefinition, _Definition {
weak var forwardsToDefinition: _TypeForwardingDefinition? { get set }
var forwardsFromDefinitions: [_TypeForwardingDefinition] { get set }
func implements(type: Any.Type)
func implements(type: [Any.Type])
weak var forwardsTo: _TypeForwardingDefinition? { get set }
var forwardsFrom: [_TypeForwardingDefinition] { get set }
func _implements(_ type: Any.Type)
func _implements(_ type: [Any.Type])
}
extension DefinitionOf: _TypeForwardingDefinition {
extension Definition: _TypeForwardingDefinition {
var type: Any.Type {
return T.self
}
}
extension DefinitionOf: CustomStringConvertible {
extension Definition: CustomStringConvertible {
public var description: String {
return "type: \(T.self), factory: \(F.self), scope: \(scope)"
}
@@ -303,30 +325,62 @@ extension DefinitionOf: CustomStringConvertible {
//MARK: - Definition Builder
/// Internal class used to build definition
/// Need this builder as alternative to changing to DefinitionOf<T, U> where U - type of arguments
class DefinitionBuilder<T, U> {
typealias F = U throws -> T
typealias F = (U) throws -> T
var scope: ComponentScope!
var factory: F!
var numberOfArguments: Int?
var numberOfArguments: Int = 0
var autoWiringFactory: ((DependencyContainer, DependencyContainer.Tag?) throws -> T)?
var forwardsDefinition: _Definition?
var forwardsTo: _Definition?
init(@noescape configure: (DefinitionBuilder -> ())) {
init(configure: (DefinitionBuilder) -> ()) {
configure(self)
}
func build() -> DefinitionOf<T, F> {
let factory = self.factory
let definition = DefinitionOf<T, F>(scope: scope, factory: factory)
func build() -> Definition<T, U> {
let factory = self.factory!
let definition = Definition<T, U>(scope: scope, factory: factory)
definition.numberOfArguments = numberOfArguments
definition.autoWiringFactory = autoWiringFactory
definition.weakFactory = { try factory($0 as! U) }
definition.forwardsToDefinition = forwardsDefinition as? _TypeForwardingDefinition
definition.forwardsTo = forwardsTo as? _TypeForwardingDefinition
return definition
}
}
//MARK: - KeyDefinitionPair
typealias KeyDefinitionPair = (key: DefinitionKey, definition: _Definition)
/// Definitions are matched if they are registered for the same tag and thier factories accept the same number of runtime arguments.
private func ~=(lhs: KeyDefinitionPair, rhs: KeyDefinitionPair) -> Bool {
guard lhs.key.type == rhs.key.type else { return false }
guard lhs.key.tag == rhs.key.tag else { return false }
guard lhs.definition.numberOfArguments == rhs.definition.numberOfArguments else { return false }
return true
}
/// Returns key-defintion pairs with definitions able to resolve that type (directly or via type forwarding)
/// and which tag matches provided key's tag or is nil.
/// In the end filters defintions by type of runtime arguments.
func filter(_ definitions: [KeyDefinitionPair], byKey key: DefinitionKey, byTypeOfArguments: Bool = false) -> [KeyDefinitionPair] {
let definitions = definitions
.filter({ $0.key.type == key.type || $0.definition.doesImplements(key.type) })
.filter({ $0.key.tag == key.tag || $0.key.tag == nil })
if byTypeOfArguments {
return definitions.filter({ $0.key.typeOfArguments == key.typeOfArguments })
}
else {
return definitions
}
}
/// Orders key-definition pairs putting first definitions registered for provided tag.
func order(_ definitions: [KeyDefinitionPair], byTag tag: DependencyContainer.Tag?) -> [KeyDefinitionPair] {
return
definitions.filter({ $0.key.tag == tag }) +
definitions.filter({ $0.key.tag != tag })
}
+203 -137
View File
@@ -40,15 +40,15 @@ public final class DependencyContainer {
}
internal(set) public var context: Context!
var definitions = [DefinitionKey : _Definition]()
private var resolvedInstances = ResolvedInstances()
var definitions = [DefinitionKey: _Definition]()
fileprivate var resolvedInstances = ResolvedInstances()
private let lock = RecursiveLock()
private(set) var bootstrapped = false
private var bootstrapQueue: [() throws -> ()] = []
fileprivate(set) var bootstrapped = false
fileprivate var bootstrapQueue: [() throws -> ()] = []
private var _weakCollaborators: [WeakBox<DependencyContainer>] = []
private(set) var _collaborators: [DependencyContainer] {
fileprivate(set) var _collaborators: [DependencyContainer] {
get {
return _weakCollaborators.flatMap({ $0.value })
}
@@ -64,11 +64,22 @@ public final class DependencyContainer {
- note: The `configBlock` is simply called at the end of the `init` to let you configure everything.
It is only present for convenience to have a cleaner syntax when declaring and initializing
your `DependencyContainer` instances.
your `DependencyContainer` instances.
- warning: If you use `configBlock` you need to make sure you don't create retain cycles. For example
there will be a retain cycle between container and its definition if you reference container
inside definition's factory. You can avoid that by using unowned reference to container:
```swift
let container = DependencyContainer() { container in
unowned let container = container
//register definitions
}
```
- returns: A new DependencyContainer.
*/
public init(@noescape configBlock: (DependencyContainer->()) = { _ in }) {
public init(configBlock: (DependencyContainer)->() = { _ in }) {
configBlock(self)
}
@@ -88,7 +99,7 @@ public final class DependencyContainer {
}
}
private func threadSafe<T>(@noescape closure: () throws -> T) rethrows -> T {
fileprivate func threadSafe<T>(_ closure: () throws -> T) rethrows -> T {
lock.lock()
defer {
lock.unlock()
@@ -124,7 +135,7 @@ extension DependencyContainer {
container.register {
//container will pass through the tag ("tag") used to resolve SomeService to resolve $0
SomeServiceImp(dependency: $0) as SomeService
}.resolveDependencies { container, service in
}.resolvingProperties { container, service in
//container will use `nil` tag to resolve this dependency
self.dependency = try container.resolve() as SomeDependency
@@ -143,12 +154,12 @@ extension DependencyContainer {
/// Currently resolving type.
public var resolvingType: Any.Type {
return key.protocolType
return key.type
}
/// The tag used to resolve currently resolving type.
public var tag: Tag? {
return key.associatedTag
return key.tag
}
/// The type that caused currently resolving type to be resolved.
@@ -171,7 +182,7 @@ extension DependencyContainer {
}
public var description: String {
let resolvingDescription = "Resolving type \(key.protocolType) with arguments \(key.argumentsType) tagged with \(key.associatedTag.desc)"
let resolvingDescription = "Resolving type \(key.type) with arguments \(key.typeOfArguments) tagged with \(key.tag.desc)"
if injectedInProperty != nil {
return "\(resolvingDescription) while auto-injecting property \(injectedInProperty.desc) of \(injectedInType.desc)"
}
@@ -186,9 +197,8 @@ extension DependencyContainer {
}
/// Pushes new context created with provided values and calls block. When block returns previous context is restored.
/// For `nil` values (except tag) new context will use values from the current context.
/// Will releas resolved instances and call `Resolvable` callbacks when popped to initial context.
func inContext<T>(key: DefinitionKey, injectedInProperty: String? = nil, injectedInType: Any.Type? = nil, logErrors: Bool! = nil, @noescape block: () throws -> T) rethrows -> T {
/// When popped to initial (root) context will release all references to resolved instances and call `Resolvable` callbacks.
func inContext<T>(_ key: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String? = nil, logErrors: Bool! = nil, block: () throws -> T) rethrows -> T {
return try threadSafe {
let currentContext = self.context
@@ -200,12 +210,12 @@ extension DependencyContainer {
resolvedInstances.resolvedInstances.removeAll()
for (key, instance) in resolvedInstances.weakSingletons {
if resolvedInstances.weakSingletons[key] is WeakBoxType { continue }
resolvedInstances.weakSingletons[key] = WeakBox(value: instance)
resolvedInstances.weakSingletons[key] = WeakBox(instance)
}
// We call didResolveDependencies only at this point
// because this is a point when dependencies graph is complete.
for resolvedInstance in resolvedInstances.resolvableInstances.reverse() {
for resolvedInstance in resolvedInstances.resolvableInstances.reversed() {
resolvedInstance.didResolveDependencies()
}
resolvedInstances.resolvableInstances.removeAll()
@@ -214,7 +224,7 @@ extension DependencyContainer {
context = Context(
key: key,
injectedInType: injectedInType ?? currentContext?.resolvingType,
injectedInType: injectedInType,
injectedInProperty: injectedInProperty
)
context.logErrors = logErrors ?? currentContext?.logErrors ?? true
@@ -239,32 +249,52 @@ extension DependencyContainer {
Register factory for type `T` and associate it with an optional tag.
- parameters:
- scope: The scope to use for instance created by the factory. Default value is `Shared`.
- type: Type to register definition for. Default value is return value of factory.
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
- scope: The scope to use for instance created by the factory.
- factory: The factory to register.
- factory: The factory that produces instance of `type`. Will be used to resolve instances of `type`.
- returns: A registered definition.
- note: You should cast the factory return type to the protocol you want to register it for
(unless you want to register concrete type).
(unless you want to register concrete type) or provide `type` parameter.
- seealso: `Definition`, `ComponentScope`, `DependencyTagConvertible`
**Example**:
```swift
//Register ServiceImp as Service
container.register { ServiceImp() as Service }
//Register ServiceImp as Service named by "service"
container.register(tag: "service") { ServiceImp() as Service }
container.register(.ObjectGraph) { ServiceImp() as Service }
//Register unique ServiceImp as Service
container.register(.unique) { ServiceImp() as Service }
//Register ClientImp as Client and resolve it's service dependency
container.register { try ClientImp(service: container.resolve() as Service) as Client }
//Register ServiceImp as concrete type
container.register { ServiceImp() }
container.register(factory: ServiceImp.init)
//Register ServiceImp as Service
container.register(Service.self, factory: ServiceImp.init)
//Register ClientImp as Client
container.register(Client.self, factory: ClientImp.init(service:))
```
*/
public func register<T>(tag tag: DependencyTagConvertible? = nil, _ scope: ComponentScope = .Prototype, factory: () throws -> T) -> DefinitionOf<T, () throws -> T> {
@discardableResult public func register<T>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping () throws -> T) -> Definition<T, ()> {
let definition = DefinitionBuilder<T, ()> {
$0.scope = scope
$0.factory = factory
}.build()
register(definition, forTag: tag)
register(definition, tag: tag)
return definition
}
/**
Register generic factory and auto-wiring factory and associate it with an optional tag.
@@ -282,8 +312,8 @@ extension DependencyContainer {
than _Dip_ supports (currently it's up to six) like in the following example:
```swift
public func register<T, A, B, C, ...>(tag: Tag? = nil, scope: ComponentScope = .Prototype, factory: (A, B, C, ...) throws -> T) -> DefinitionOf<T, (A, B, C, ...) throws -> T> {
return registerFactory(tag: tag, scope: scope, factory: factory, numberOfArguments: ...) { container, tag in
public func register<T, A, B, C, ...>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: Tag? = nil, factory: (A, B, C, ...) throws -> T) -> Definition<T, (A, B, C, ...)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: ...) { container, tag in
try factory(container.resolve(tag: tag), ...)
}
}
@@ -291,14 +321,14 @@ extension DependencyContainer {
Though before you do so you should probably review your design and try to reduce number of depnedencies.
*/
public func registerFactory<T, U>(tag tag: DependencyTagConvertible? = nil, scope: ComponentScope, factory: U throws -> T, numberOfArguments: Int, autoWiringFactory: (DependencyContainer, Tag?) throws -> T) -> DefinitionOf<T, U throws -> T> {
public func register<T, U>(scope: ComponentScope, type: T.Type, tag: DependencyTagConvertible?, factory: @escaping (U) throws -> T, numberOfArguments: Int, autoWiringFactory: @escaping (DependencyContainer, Tag?) throws -> T) -> Definition<T, U> {
let definition = DefinitionBuilder<T, U> {
$0.scope = scope
$0.factory = factory
$0.numberOfArguments = numberOfArguments
$0.autoWiringFactory = autoWiringFactory
}.build()
register(definition, forTag: tag)
register(definition, tag: tag)
return definition
}
@@ -311,22 +341,23 @@ extension DependencyContainer {
- definition: The definition to register in the container.
*/
public func register<T, U>(definition: DefinitionOf<T, U throws -> T>, forTag tag: DependencyTagConvertible? = nil) {
let key = DefinitionKey(protocolType: T.self, argumentsType: U.self, associatedTag: tag?.dependencyTag)
register(definition, forKey: key)
if case .EagerSingleton = definition.scope {
bootstrapQueue.append({ let _ = try self.resolve(tag: tag) as T })
}
}
/// Actually register definition
func register(definition: _Definition, forKey key: DefinitionKey) {
public func register<T, U>(_ definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
precondition(!bootstrapped, "You can not modify container's definitions after it was bootstrapped.")
threadSafe {
let key = DefinitionKey(type: T.self, typeOfArguments: U.self, tag: tag?.dependencyTag)
if let _ = definitions[key] {
remove(definitionForKey: key)
}
definition.container = self
definitions[key] = definition
resolvedInstances.singletons[key] = nil
resolvedInstances.weakSingletons[key] = nil
if case .eagerSingleton = definition.scope {
bootstrapQueue.append({ let _ = try self.resolve(tag: tag) as T })
}
}
}
@@ -337,19 +368,17 @@ extension DependencyContainer {
extension DependencyContainer {
/**
Resolve a an instance of type `T`.
Resolve an instance of type `T`.
If no matching definition was registered with provided `tag`,
container will lookup definition associated with `nil` tag.
- parameter tag: The arbitrary tag to use to lookup definition.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of type `T`.
- seealso: `register(tag:_:factory:)`
**Example**:
```swift
let service = try! container.resolve() as Service
@@ -357,27 +386,36 @@ extension DependencyContainer {
let service: Service = try! container.resolve()
```
- seealso: `register(_:type:tag:factory:)`
*/
public func resolve<T>(tag tag: DependencyTagConvertible? = nil) throws -> T {
public func resolve<T>(tag: DependencyTagConvertible? = nil) throws -> T {
return try resolve(tag: tag) { factory in try factory() }
}
/**
Resolve an instance of provided type. Weakly-typed alternative of `resolve(tag:)`
Resolve an instance of requested type. Weakly-typed alternative of `resolve(tag:)`
- warning: This method does not make any type checks, so there is no guaranty that
resulting instance is actually an instance of requested type.
That can happen if you register forwarded type that is not implemented by resolved instance.
- parameters:
- type: Type to resolve
- tag: The arbitrary tag to use to lookup definition.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of requested type.
**Example**:
```swift
let service = try! container.resolve(Service.self) as! Service
let service = try! container.resolve(Service.self, tag: "service") as! Service
```
- seealso: `resolve(tag:)`, `register(tag:_:factory:)`
- seealso: `resolve(tag:)`, `register(_:type:tag:factory:)`
*/
public func resolve(type: Any.Type, tag: DependencyTagConvertible? = nil) throws -> Any {
public func resolve(_ type: Any.Type, tag: DependencyTagConvertible? = nil) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory() }
}
@@ -388,7 +426,7 @@ extension DependencyContainer {
- tag: The arbitrary tag to use to lookup definition.
- builder: Generic closure that accepts generic factory and returns inctance created by that factory.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of type `T`.
@@ -398,14 +436,14 @@ extension DependencyContainer {
_Dip_ supports (currently it's up to six) like in the following example:
```swift
public func resolve<T, A, B, C, ...>(tag tag: Tag? = nil, _ arg1: A, _ arg2: B, _ arg3: C, ...) throws -> T {
public func resolve<T, A, B, C, ...>(tag: Tag? = nil, _ arg1: A, _ arg2: B, _ arg3: C, ...) throws -> T {
return try resolve(tag: tag) { factory in factory(arg1, arg2, arg3, ...) }
}
```
Though before you do so you should probably review your design and try to reduce the number of dependencies.
*/
public func resolve<T, U>(tag tag: DependencyTagConvertible? = nil, builder: (U throws -> T) throws -> T) rethrows -> T {
public func resolve<T, U>(tag: DependencyTagConvertible? = nil, builder: ((U) throws -> T) throws -> T) throws -> T {
return try resolve(T.self, tag: tag, builder: { factory in
try builder({ try factory($0) as! T })
}) as! T
@@ -416,20 +454,20 @@ extension DependencyContainer {
- seealso: `resolve(tag:builder:)`
*/
public func resolve<U>(type: Any.Type, tag: DependencyTagConvertible? = nil, builder: (U throws -> Any) throws -> Any) rethrows -> Any {
let key = DefinitionKey(protocolType: type, argumentsType: U.self, associatedTag: tag?.dependencyTag)
public func resolve<U>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
let key = DefinitionKey(type: type, typeOfArguments: U.self, tag: tag?.dependencyTag)
return try inContext(key) {
try resolveKey(key, builder: { definition in
return try inContext(key, injectedInType: context?.resolvingType) {
try resolve(key: key, builder: { definition in
try builder(definition.weakFactory)
})
}
}
/// Lookup definition by the key and use it to resolve instance. Fallback to the key with `nil` tag.
func resolveKey<T>(key: DefinitionKey, builder: (_Definition throws -> T)) throws -> T {
func resolve<T>(key: DefinitionKey, builder: (_Definition) throws -> T) throws -> T {
guard let matching = self.definition(matching: key) else {
return try resolveWithCollaborators(key, builder: builder) ?? autowire(key)
return try resolveCollaborating(key, builder: builder) ?? autowire(key)
}
let (key, definition) = matching
@@ -456,7 +494,7 @@ extension DependencyContainer {
That happens because when Optional is casted to Any Swift can not implicitly unwrap it with as operator.
As a workaround we detect boxing here and unwrap it so that we return not a box, but wrapped instance.
*/
if let box = resolvedInstance as? BoxType, unboxed = box.unboxed as? T {
if let box = resolvedInstance as? BoxType, let unboxed = box.unboxed as? T {
resolvedInstance = unboxed
}
@@ -468,25 +506,31 @@ extension DependencyContainer {
return previouslyResolved
}
resolvedInstances[forKey: key, inScope: definition.scope] = resolvedInstance
resolvedInstances[key: key, inScope: definition.scope] = resolvedInstance
if let resolvable = resolvedInstance as? Resolvable {
resolvedInstances.resolvableInstances.append(resolvable)
resolvable.resolveDependencies(self)
}
try autoInjectProperties(resolvedInstance)
try definition.resolveDependenciesOf(resolvedInstance, withContainer: self)
try definition.resolveProperties(of: resolvedInstance, container: self)
log(.Verbose, "Resolved type \(key.protocolType) with \(resolvedInstance)")
log(.Verbose, "Resolved type \(key.type) with \(resolvedInstance)")
return resolvedInstance
}
private func previouslyResolved<T>(definition: _Definition, key: DefinitionKey) -> T? {
private func previouslyResolved<T>(_ definition: _Definition, key: DefinitionKey) -> T? {
//first check if exact key was already resolved
if let previouslyResolved = resolvedInstances[key: key, inScope: definition.scope] as? T {
return previouslyResolved
}
//then check if any related type was already resolved
let keys = definition.implementingTypes.map({
DefinitionKey(protocolType: $0, argumentsType: key.argumentsType, associatedTag: key.associatedTag)
DefinitionKey(type: $0, typeOfArguments: key.typeOfArguments, tag: key.tag)
})
for key in [key] + keys {
if let previouslyResolved = resolvedInstances[forKey: key, inScope: definition.scope] as? T {
for key in keys {
if let previouslyResolved = resolvedInstances[key: key, inScope: definition.scope] as? T {
return previouslyResolved
}
}
@@ -495,15 +539,15 @@ extension DependencyContainer {
/// Searches for definition that matches provided key
private func definition(matching key: DefinitionKey) -> KeyDefinitionPair? {
let typeDefinitions = definitions.filter({ $0.0.protocolType == key.protocolType })
guard !typeDefinitions.isEmpty else {
return typeForwardingDefinition(key)
}
if let definition = (self.definitions[key] ?? self.definitions[key.tagged(nil)]) {
return (key, definition)
}
//if no definition registered for exact type try to find type-forwarding definition that can resolve the type
//that will actually happen only when resolving optionals
if definitions.filter({ $0.0.type == key.type }).isEmpty {
return typeForwardingDefinition(key)
}
return nil
}
@@ -527,20 +571,24 @@ extension DependencyContainer {
*/
public func collaborate(with containers: [DependencyContainer]) {
_collaborators += containers
for container in containers {
container.resolvedInstances.singletonsBox = self.resolvedInstances.singletonsBox
container.resolvedInstances.weakSingletonsBox = self.resolvedInstances.weakSingletonsBox
}
}
/// Tries to resolve key using collaborating containers
private func resolveWithCollaborators<T>(key: DefinitionKey, builder: _Definition throws -> T) -> T? {
fileprivate func resolveCollaborating<T>(_ key: DefinitionKey, builder: (_Definition) throws -> T) -> T? {
for collaborator in _collaborators {
//if container is already in a context resolving this type
//it means that it has been already called to resolve this type,
//so there is probably a cercular reference between containers.
//To break it skip this container
if let context = collaborator.context,
context.resolvingType == key.type &&
context.tag == key.tag { continue }
do {
//if container is already in a context resolving this type
//it means that it has been already called to resolve this type,
//so there is probably a cercular reference between containers.
//To break it skip this container
if let context = collaborator.context where
context.resolvingType == key.protocolType &&
context.tag == key.associatedTag { continue }
//Pass current container's instances pool to collect instances resolved by collaborator
let resolvedInstances = collaborator.resolvedInstances
collaborator.resolvedInstances = self.resolvedInstances
@@ -552,15 +600,13 @@ extension DependencyContainer {
collaborator.context = context
}
let resolved = try collaborator.inContext(key, injectedInProperty: self.context.injectedInProperty, injectedInType: self.context.injectedInType, logErrors: false) {
try collaborator.resolveKey(key, builder: builder)
let resolved = try collaborator.inContext(key, injectedInType: self.context.injectedInType, injectedInProperty: self.context.injectedInProperty, logErrors: false) {
try collaborator.resolve(key: key, builder: builder)
}
return resolved
}
catch {
continue
}
catch { }
}
return nil
}
@@ -578,17 +624,19 @@ extension DependencyContainer {
- tag: The tag used to register definition.
- definition: The definition to remove
*/
public func remove<T, U>(definition: DefinitionOf<T, U>, forTag tag: DependencyTagConvertible? = nil) {
let key = DefinitionKey(protocolType: T.self, argumentsType: U.self, associatedTag: tag?.dependencyTag)
public func remove<T, U>(_ definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
let key = DefinitionKey(type: T.self, typeOfArguments: U.self, tag: tag?.dependencyTag)
remove(definitionForKey: key)
}
private func remove(definitionForKey key: DefinitionKey) {
fileprivate func remove(definitionForKey key: DefinitionKey) {
precondition(!bootstrapped, "You can not modify container's definitions after it was bootstrapped.")
threadSafe {
definitions[key]?.container = nil
definitions[key] = nil
resolvedInstances.singletons[key] = nil
resolvedInstances.weakSingletons[key] = nil
}
}
@@ -597,8 +645,10 @@ extension DependencyContainer {
*/
public func reset() {
threadSafe {
definitions.forEach { $0.1.container = nil }
definitions.removeAll()
resolvedInstances.singletons.removeAll()
resolvedInstances.weakSingletons.removeAll()
bootstrapped = false
}
}
@@ -616,14 +666,14 @@ extension DependencyContainer {
- parameter arguments: set of arguments to use to resolve registered definitions.
Use a tuple for registered factories that accept several runtime arguments.
*/
public func validate(arguments: Any...) throws {
public func validate(_ arguments: Any...) throws {
validateNextDefinition: for (key, _) in definitions {
do {
//try to resolve key using provided arguments
for argumentsSet in arguments where argumentsSet.dynamicType == key.argumentsType {
for argumentsSet in arguments where type(of: argumentsSet) == key.typeOfArguments {
do {
try inContext(key) {
try resolveKey(key, builder: { definition throws -> Any in
let _ = try inContext(key, injectedInType: nil) {
try resolve(key: key, builder: { definition throws -> Any in
try definition.weakFactory(argumentsSet)
})
}
@@ -638,7 +688,7 @@ extension DependencyContainer {
//try to resolve key using auto-wiring
do {
try self.resolve(key.protocolType, tag: key.associatedTag)
let _ = try self.resolve(key.type, tag: key.tag)
}
catch let error as DipError {
throw error
@@ -653,26 +703,37 @@ extension DependencyContainer {
///Pool to hold instances, created during call to `resolve()`.
///Before `resolve()` returns pool is drained.
private class ResolvedInstances {
var resolvedInstances = [DefinitionKey: Any]()
var singletons = [DefinitionKey: Any]()
var weakSingletons = [DefinitionKey: Any]()
var resolvableInstances = [Resolvable]()
subscript(forKey key: DefinitionKey, inScope scope: ComponentScope) -> Any? {
//singletons are stored using reference type wrapper to be able to share them between containers
fileprivate var singletonsBox = Box<[DefinitionKey: Any]>([:])
var singletons: [DefinitionKey: Any] {
get { return singletonsBox.unboxed }
set { singletonsBox.unboxed = newValue }
}
fileprivate var weakSingletonsBox = Box<[DefinitionKey: Any]>([:])
var weakSingletons: [DefinitionKey: Any] {
get { return weakSingletonsBox.unboxed }
set { weakSingletonsBox.unboxed = newValue }
}
subscript(key key: DefinitionKey, inScope scope: ComponentScope) -> Any? {
get {
switch scope {
case .Singleton, .EagerSingleton: return singletons[key]
case .WeakSingleton: return (weakSingletons[key] as? WeakBoxType)?.unboxed ?? weakSingletons[key]
case .ObjectGraph: return resolvedInstances[key]
case .Prototype: return nil
case .singleton, .eagerSingleton: return singletons[key]
case .weakSingleton: return (weakSingletons[key] as? WeakBoxType)?.unboxed ?? weakSingletons[key]
case .shared: return resolvedInstances[key]
case .unique: return nil
}
}
set {
switch scope {
case .Singleton, .EagerSingleton: singletons[key] = newValue
case .WeakSingleton: weakSingletons[key] = newValue
case .ObjectGraph: resolvedInstances[key] = newValue
case .Prototype: break
case .singleton, .eagerSingleton: singletons[key] = newValue
case .weakSingleton: weakSingletons[key] = newValue
case .shared: resolvedInstances[key] = newValue
case .unique: break
}
}
}
@@ -682,22 +743,30 @@ private class ResolvedInstances {
extension DependencyContainer: CustomStringConvertible {
public var description: String {
return "Definitions: \(definitions.count)\n" + definitions.map({ "\($0.0)" }).joinWithSeparator("\n")
return "Definitions: \(definitions.count)\n" + definitions.map({ "\($0.0)" }).joined(separator: "\n")
}
}
//MARK: - Resolvable
/// Conform to this protocol when you need to have a callback when all the dependencies are injected.
/// Resolvable protocol provides some extension points for resolving dependencies with property injection.
public protocol Resolvable {
/// This method is called by the container when all dependencies of the instance are resolved.
/// This method will be called right after instance is created by the container.
func resolveDependencies(_ container: DependencyContainer)
/// This method will be called when all dependencies of the instance are resolved.
/// When resolving objects graph the last resolved instance will receive this callback first.
func didResolveDependencies()
}
public extension Resolvable {
func resolveDependencies(_ container: DependencyContainer) { }
func didResolveDependencies() { }
}
//MARK: - DependencyTagConvertible
/// Implement this protocol of your type if you want to use its instances as `DependencyContainer`'s tags.
/// Implement this protocol on your type if you want to use its instances as `DependencyContainer`'s tags.
/// `DependencyContainer.Tag`, `String`, `Int` and any `RawRepresentable` with `RawType` of `String` or `Int` by default confrom to this protocol.
public protocol DependencyTagConvertible {
var dependencyTag: DependencyContainer.Tag { get }
@@ -733,7 +802,7 @@ extension DependencyTagConvertible where Self: RawRepresentable, Self.RawValue =
}
}
extension DependencyContainer.Tag: StringLiteralConvertible {
extension DependencyContainer.Tag: ExpressibleByStringLiteral {
public init(stringLiteral value: StringLiteralType) {
self = .String(value)
@@ -749,7 +818,7 @@ extension DependencyContainer.Tag: StringLiteralConvertible {
}
extension DependencyContainer.Tag: IntegerLiteralConvertible {
extension DependencyContainer.Tag: ExpressibleByIntegerLiteral {
public init(integerLiteral value: IntegerLiteralType) {
self = .Int(value)
@@ -775,14 +844,14 @@ public func ==(lhs: DependencyContainer.Tag, rhs: DependencyContainer.Tag) -> Bo
- seealso: `resolve(tag:)`
*/
public enum DipError: ErrorType, CustomStringConvertible {
public enum DipError: Error, CustomStringConvertible {
/**
Thrown by `resolve(tag:)` if no matching definition was registered in container.
- parameter key: definition key used to lookup matching definition
*/
case DefinitionNotFound(key: DefinitionKey)
case definitionNotFound(key: DefinitionKey)
/**
Thrown by `resolve(tag:)` if failed to auto-inject required property.
@@ -792,7 +861,7 @@ public enum DipError: ErrorType, CustomStringConvertible {
- type: The type of the property
- underlyingError: The error that caused auto-injection to fail
*/
case AutoInjectionFailed(label: String?, type: Any.Type, underlyingError: ErrorType)
case autoInjectionFailed(label: String?, type: Any.Type, underlyingError: Error)
/**
Thrown by `resolve(tag:)` if failed to auto-wire a type.
@@ -801,8 +870,8 @@ public enum DipError: ErrorType, CustomStringConvertible {
- type: The type that failed to be resolved by auto-wiring
- underlyingError: The error that cause auto-wiring to fail
*/
case AutoWiringFailed(type: Any.Type, underlyingError: ErrorType)
case autoWiringFailed(type: Any.Type, underlyingError: Error)
/**
Thrown when auto-wiring type if several definitions with the same number of runtime arguments
are registered for that type.
@@ -811,34 +880,31 @@ public enum DipError: ErrorType, CustomStringConvertible {
- type: The type that failed to be resolved by auto-wiring
- definitions: Ambiguous definitions
*/
case AmbiguousDefinitions(type: Any.Type, definitions: [Definition])
case ambiguousDefinitions(type: Any.Type, definitions: [DefinitionType])
/**
Thrown by `resolve(tag:)` if resolved instance does not implemenet resolved type (i.e. when type-forwarding).
- parameters:
- resolved: Resolved instance
- key: Definition key used to resolve instance
*/
case invalidType(resolved: Any?, key: DefinitionKey)
public var description: String {
switch self {
case let .DefinitionNotFound(key):
return "No definition registered for \(key).\nCheck the tag, type you try to resolve, number, order and types of runtime arguments passed to `resolve()` and match them with registered factories for type \(key.protocolType)."
case let .AutoInjectionFailed(label, type, error):
case let .definitionNotFound(key):
return "No definition registered for \(key).\nCheck the tag, type you try to resolve, number, order and types of runtime arguments passed to `resolve()` and match them with registered factories for type \(key.type)."
case let .autoInjectionFailed(label, type, error):
return "Failed to auto-inject property \"\(label.desc)\" of type \(type). \(error)"
case let .AutoWiringFailed(type, error):
case let .autoWiringFailed(type, error):
return "Failed to auto-wire type \"\(type)\". \(error)"
case let .AmbiguousDefinitions(type, definitions):
case let .ambiguousDefinitions(type, definitions):
return "Ambiguous definitions for \(type):\n" +
definitions.map({ "\($0)" }).joinWithSeparator(";\n")
definitions.map({ "\($0)" }).joined(separator: ";\n")
case let .invalidType(resolved, key):
return "Resolved instance \(resolved ?? "nil") does not implement expected type \(key.type)."
}
}
}
//MARK: - Deprecated methods
extension DependencyContainer {
@available(*, deprecated=4.3.0, message="Use registerFactory(tag:scope:factory:numberOfArguments:autoWiringFactory:) instead.")
public func registerFactory<T, U>(tag tag: DependencyTagConvertible? = nil, scope: ComponentScope, factory: U throws -> T) -> DefinitionOf<T, U throws -> T> {
let definition = DefinitionBuilder<T, U> {
$0.scope = scope
$0.factory = factory
}.build()
register(definition, forTag: tag)
return definition
}
}
+35 -36
View File
@@ -37,15 +37,15 @@ extension DependencyContainer {
- parameters:
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
- scope: The scope to use for this component. Default value is `.Prototype`.
- scope: The scope to use for this component. Default value is `Shared`.
- factory: The factory to register.
- seealso: `registerFactory(tag:scope:factory:)`
- seealso: `register(_:type:tag:factory:)`
*/
public func register<T, A>(tag tag: DependencyTagConvertible? = nil, _ scope: ComponentScope = .Prototype, factory: (A) throws -> T) -> DefinitionOf<T, (A) throws -> T> {
return registerFactory(tag: tag, scope: scope, factory: factory, numberOfArguments: 1) { container, tag in try factory(container.resolve(tag: tag)) }
@discardableResult public func register<T, A>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A) throws -> T) -> Definition<T, A> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 1) { container, tag in try factory(container.resolve(tag: tag)) }
}
/**
Resolve type `T` using one runtime argument.
@@ -70,99 +70,98 @@ extension DependencyContainer {
- seealso: `register(tag:_:factory:)`, `resolve(tag:builder:)`
*/
public func resolve<T, A>(tag tag: DependencyTagConvertible? = nil, withArguments arg1: A) throws -> T {
public func resolve<T, A>(tag: DependencyTagConvertible? = nil, arguments arg1: A) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:withArguments:)`
public func resolve<A>(type: Any.Type, tag: DependencyTagConvertible? = nil, withArguments arg1: A) throws -> Any {
public func resolve<A>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory(arg1) }
}
// MARK: 2 Runtime Arguments
/// - seealso: `register(tag:scope:factory:)`
public func register<T, A, B>(tag tag: DependencyTagConvertible? = nil, _ scope: ComponentScope = .Prototype, factory: (A, B) throws -> T) -> DefinitionOf<T, (A, B) throws -> T> {
return registerFactory(tag: tag, scope: scope, factory: factory, numberOfArguments: 2) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag)) }
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B) throws -> T) -> Definition<T, (A, B)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 2) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:withArguments:)`
public func resolve<T, A, B>(tag tag: DependencyTagConvertible? = nil, withArguments arg1: A, _ arg2: B) throws -> T {
public func resolve<T, A, B>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:withArguments:)`
public func resolve<A, B>(type: Any.Type, tag: DependencyTagConvertible? = nil, withArguments arg1: A, _ arg2: B) throws -> Any {
public func resolve<A, B>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2)) }
}
// MARK: 3 Runtime Arguments
/// - seealso: `register(tag:scope:factory:)`
public func register<T, A, B, C>(tag tag: DependencyTagConvertible? = nil, _ scope: ComponentScope = .Prototype, factory: (A, B, C) throws -> T) -> DefinitionOf<T, (A, B, C) throws -> T> {
return registerFactory(tag: tag, scope: scope, factory: factory, numberOfArguments: 3) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
@discardableResult public func register<T, A, B, C>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C) throws -> T) -> Definition<T, (A, B, C)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 3) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:withArguments:)`
public func resolve<T, A, B, C>(tag tag: DependencyTagConvertible? = nil, withArguments arg1: A, _ arg2: B, _ arg3: C) throws -> T {
public func resolve<T, A, B, C>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:withArguments:)`
public func resolve<A, B, C>(type: Any.Type, tag: DependencyTagConvertible? = nil, withArguments arg1: A, _ arg2: B, _ arg3: C) throws -> Any {
public func resolve<A, B, C>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3)) }
}
// MARK: 4 Runtime Arguments
/// - seealso: `register(tag:scope:factory:)`
public func register<T, A, B, C, D>(tag tag: DependencyTagConvertible? = nil, _ scope: ComponentScope = .Prototype, factory: (A, B, C, D) throws -> T) -> DefinitionOf<T, (A, B, C, D) throws -> T> {
return registerFactory(tag: tag, scope: scope, factory: factory, numberOfArguments: 4) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
@discardableResult public func register<T, A, B, C, D>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C, D) throws -> T) -> Definition<T, (A, B, C, D)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 4) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:withArguments:)`
public func resolve<T, A, B, C, D>(tag tag: DependencyTagConvertible? = nil, withArguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D) throws -> T {
public func resolve<T, A, B, C, D>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4) }
}
/// - seealso: `resolve(_:tag:)`, `resolve(tag:withArguments:)`
public func resolve<A, B, C, D>(type: Any.Type, tag: DependencyTagConvertible? = nil, withArguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D) throws -> Any {
public func resolve<A, B, C, D>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4)) }
}
// MARK: 5 Runtime Arguments
/// - seealso: `register(tag:scope:factory:)`
public func register<T, A, B, C, D, E>(tag tag: DependencyTagConvertible? = nil, _ scope: ComponentScope = .Prototype, factory: (A, B, C, D, E) throws -> T) -> DefinitionOf<T, (A, B, C, D, E) throws -> T> {
return registerFactory(tag: tag, scope: scope, factory: factory, numberOfArguments: 5) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
@discardableResult public func register<T, A, B, C, D, E>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C, D, E) throws -> T) -> Definition<T, (A, B, C, D, E)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 5) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:withArguments:)`
public func resolve<T, A, B, C, D, E>(tag tag: DependencyTagConvertible? = nil, withArguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E) throws -> T {
public func resolve<T, A, B, C, D, E>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4, arg5) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:withArguments:)`
public func resolve<A, B, C, D, E>(type: Any.Type, tag: DependencyTagConvertible? = nil, withArguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E) throws -> Any {
public func resolve<A, B, C, D, E>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5)) }
}
// MARK: 6 Runtime Arguments
/// - seealso: `register(tag:scope:factory:)`
public func register<T, A, B, C, D, E, F>(tag tag: DependencyTagConvertible? = nil, _ scope: ComponentScope = .Prototype, factory: (A, B, C, D, E, F) throws -> T) -> DefinitionOf<T, (A, B, C, D, E, F) throws -> T> {
return registerFactory(tag: tag, scope: scope, factory: factory, numberOfArguments: 6) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
@discardableResult public func register<T, A, B, C, D, E, F>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C, D, E, F) throws -> T) -> Definition<T, (A, B, C, D, E, F)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 6) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:withArguments:)`
public func resolve<T, A, B, C, D, E, F>(tag tag: DependencyTagConvertible? = nil, withArguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F) throws -> T {
public func resolve<T, A, B, C, D, E, F>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4, arg5, arg6) }
}
/// - seealso: `resolve(_:tag:)`, `resolve(tag:withArguments:)`
public func resolve<A, B, C, D, E, F>(type: Any.Type, tag: DependencyTagConvertible? = nil, withArguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F) throws -> Any {
public func resolve<A, B, C, D, E, F>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5, arg6)) }
}
}
+89 -20
View File
@@ -22,9 +22,70 @@
// THE SOFTWARE.
//
protocol TypeForwardingDefinition: Definition {
protocol TypeForwardingDefinition: DefinitionType {
var implementingTypes: [Any.Type] { get }
func doesImplements(type: Any.Type) -> Bool
func doesImplements(_ type: Any.Type) -> Bool
}
extension Definition {
/**
Registers definition for passed type.
If instance created by factory of definition on which method is called
does not implement type passed in a `type` parameter,
container will throw `DipError.DefinitionNotFound` error when trying to resolve that type.
- parameters:
- type: Type to register definition for
- tag: Optional tag to associate definition with. Default is `nil`.
- returns: definition on which `implements` was called
*/
@discardableResult public func implements<F>(_ type: F.Type, tag: DependencyTagConvertible? = nil) -> Definition {
precondition(container != nil, "Definition should be registered in the container.")
container!.register(self, type: type, tag: tag)
return self
}
/**
Registers definition for passed type.
If instance created by factory of definition on which method is called
does not implement type passed in a `type` parameter,
container will throw `DipError.DefinitionNotFound` error when trying to resolve that type.
- parameters:
- type: Type to register definition for
- tag: Optional tag to associate definition with. Default is `nil`.
- resolvingProperties: Optional block to be called to resolve instance property dependencies
- returns: definition on which `implements` was called
*/
@discardableResult public func implements<F>(_ type: F.Type, tag: DependencyTagConvertible? = nil, resolvingProperties: @escaping (DependencyContainer, F) throws -> ()) -> Definition {
precondition(container != nil, "Definition should be registered in the container.")
let forwardDefinition = container!.register(self, type: type, tag: tag)
forwardDefinition.resolvingProperties(resolvingProperties)
return self
}
///Registers definition for types passed as parameters
@discardableResult public func implements<A, B>(_ a: A.Type, _ b: B.Type) -> Definition {
return implements(a).implements(b)
}
///Registers definition for types passed as parameters
@discardableResult public func implements<A, B, C>(_ a: A.Type, _ b: B.Type, _ c: C.Type) -> Definition {
return implements(a).implements(b).implements(c)
}
///Registers definition for types passed as parameters
@discardableResult public func implements<A, B, C, D>(_ a: A.Type, _ b: B.Type, c: C.Type, d: D.Type) -> Definition {
return implements(a).implements(b).implements(c).implements(d)
}
}
extension DependencyContainer {
@@ -32,7 +93,8 @@ extension DependencyContainer {
/**
Registers definition for passed type.
If instance created by definition factory does not implement registered type
If instance created by factory of definition, passed as a first parameter,
does not implement type passed in a `type` parameter,
container will throw `DipError.DefinitionNotFound` error when trying to resolve that type.
- parameters:
@@ -40,48 +102,55 @@ extension DependencyContainer {
- type: Type to register definition for
- tag: Optional tag to associate definition with. Default is `nil`.
- returns: New definition for passed type.
- returns: New definition registered for passed type.
*/
public func register<T, U, F>(definition: DefinitionOf<T, U throws -> T>, type: F.Type, tag: DependencyTagConvertible? = nil) -> DefinitionOf<F, U throws -> F> {
let key = DefinitionKey(protocolType: F.self, argumentsType: U.self)
@discardableResult public func register<T, U, F>(_ definition: Definition<T, U>, type: F.Type, tag: DependencyTagConvertible? = nil) -> Definition<F, U> {
precondition(definition.container === self, "Definition should be registered in the container.")
let key = DefinitionKey(type: F.self, typeOfArguments: U.self)
let forwardDefinition = DefinitionBuilder<F, U> {
$0.scope = definition.scope
let factory = definition.factory
$0.factory = { [unowned self] in
guard let resolved = try factory($0) as? F else {
throw DipError.DefinitionNotFound(key: key.tagged(self.context.tag))
let resolved = try factory($0)
if let resolved = resolved as? F {
return resolved
}
else {
throw DipError.invalidType(resolved: resolved, key: key.tagged(self.context.tag))
}
return resolved
}
$0.numberOfArguments = definition.numberOfArguments
$0.autoWiringFactory = definition.autoWiringFactory.map({ autoWiringFactory in
$0.autoWiringFactory = definition.autoWiringFactory.map({ factory in
{ [unowned self] in
guard let resolved = try autoWiringFactory($0, $1) as? F else {
throw DipError.DefinitionNotFound(key: key.tagged(self.context.tag))
let resolved = try factory($0, $1)
if let resolved = resolved as? F {
return resolved
}
else {
throw DipError.invalidType(resolved: resolved, key: key.tagged(self.context.tag))
}
return resolved
}
})
$0.forwardsDefinition = definition
$0.forwardsTo = definition
}.build()
register(forwardDefinition, forTag: tag)
register(forwardDefinition, tag: tag)
return forwardDefinition
}
/// Searches for definition that forwards requested type
func typeForwardingDefinition(key: DefinitionKey) -> KeyDefinitionPair? {
func typeForwardingDefinition(_ key: DefinitionKey) -> KeyDefinitionPair? {
var forwardingDefinitions = self.definitions.map({ (key: $0.0, definition: $0.1) })
forwardingDefinitions = filter(forwardingDefinitions, type: key.protocolType, tag: key.associatedTag, argumentsType: key.argumentsType)
forwardingDefinitions = order(forwardingDefinitions, tag: key.associatedTag)
forwardingDefinitions = filter(forwardingDefinitions, byKey: key, byTypeOfArguments: true)
forwardingDefinitions = order(forwardingDefinitions, byTag: key.tag)
//we need to carry on original tag
return forwardingDefinitions.first.map({ ($0.key.tagged(key.associatedTag), $0.definition) })
return forwardingDefinitions.first.map({ ($0.key.tagged(key.tag), $0.definition) })
}
}
+41 -10
View File
@@ -22,15 +22,16 @@
// THE SOFTWARE.
//
public enum LogLevel {
case Verbose
case Errors
public enum LogLevel: Int {
case None
case Errors
case Verbose
}
public var logLevel: LogLevel = .Errors
func log(logLevel: LogLevel, _ message: Any) {
guard case logLevel = Dip.logLevel else { return }
func log(_ logLevel: LogLevel, _ message: Any) {
guard logLevel.rawValue <= Dip.logLevel.rawValue else { return }
print(message)
}
@@ -42,7 +43,7 @@ protocol BoxType {
extension Optional: BoxType {
var unboxed: Any? {
switch self {
case let .Some(value): return value
case let .some(value): return value
default: return nil
}
}
@@ -51,12 +52,19 @@ extension Optional: BoxType {
extension ImplicitlyUnwrappedOptional: BoxType {
var unboxed: Any? {
switch self {
case let .Some(value): return value
case let .some(value): return value
default: return nil
}
}
}
class Box<T> {
var unboxed: T
init(_ value: T) {
self.unboxed = value
}
}
protocol WeakBoxType {
var unboxed: AnyObject? { get }
}
@@ -67,8 +75,13 @@ class WeakBox<T>: WeakBoxType {
return unboxed as? T
}
init(value: T) {
guard let value = value as? AnyObject else {
init(_ value: T) {
#if os(Linux)
weak var value: AnyObject? = value as? AnyObject
#else
weak var value: AnyObject? = value as AnyObject
#endif
guard value != nil else {
fatalError("Can not store weak reference to not a class instance (\(T.self))")
}
self.unboxed = value
@@ -94,7 +107,25 @@ extension Optional {
}
}
extension Collection where Index: Comparable, Self.Indices.Index == Index {
subscript(safe index: Index) -> Generator.Element? {
guard indices.startIndex..<indices.endIndex ~= index else { return nil }
return self[index]
}
subscript(next index: Index) -> Generator.Element? {
return self[safe: indices.index(after: index)]
}
}
#if os(Linux)
extension String {
public func hasPrefix(_ prefix: String) -> Bool {
return prefix ==
String(self.characters.prefix(prefix.characters.count))
}
}
import Glibc
class RecursiveLock {
private var _lock = _initializeRecursiveMutex()
@@ -124,7 +155,7 @@ extension Optional {
extension pthread_mutex_t {
mutating func lock() {
pthread_mutex_trylock(&self)
pthread_mutex_lock(&self)
}
mutating func unlock() {
pthread_mutex_unlock(&self)
View File
@@ -26,13 +26,13 @@ import XCTest
@testable import Dip
private protocol Server: class {
weak var client: Client? {get}
var anotherClient: Client? {get set}
weak var client: Client! {get}
var anotherClient: Client! {get set}
}
private protocol Client: class {
var server: Server? {get}
var anotherServer: Server? {get set}
var server: Server! {get}
var anotherServer: Server! {get set}
}
private class ServerImp: Server {
@@ -40,11 +40,12 @@ private class ServerImp: Server {
var _client = InjectedWeak<Client>() { _ in
AutoInjectionTests.clientDidInjectCalled = true
}
var client: Client? {
var client: Client! {
return _client.value
}
weak var anotherClient: Client?
weak var anotherClient: Client!
weak var _optionalProperty = InjectedWeak<AnyObject>(required: false)
}
@@ -54,11 +55,12 @@ private class ClientImp: Client {
var _server = Injected<Server>() { _ in
AutoInjectionTests.serverDidInjectCalled = true
}
var server: Server? {
var server: Server! {
return _server.value
}
var anotherServer: Server?
var anotherServer: Server!
var _optionalProperty = Injected<AnyObject>(required: false)
@@ -91,10 +93,10 @@ class AutoInjectionTests: XCTestCase {
let container = DependencyContainer()
#if os(Linux)
static var allTests: [(String, AutoInjectionTests -> () throws -> Void)] {
static var allTests = {
return [
("testThatItResolvesAutoInjectedDependencies", testThatItResolvesAutoInjectedDependencies),
("testThatItResolvesInheritedDependencies", testThatItResolvesInheritedDependencies),
("testThatItCanSetInjectedProperty", testThatItCanSetInjectedProperty),
("testThatItThrowsErrorIfFailsToAutoInjectDependency", testThatItThrowsErrorIfFailsToAutoInjectDependency),
("testThatItResolvesAutoInjectedSingletons", testThatItResolvesAutoInjectedSingletons),
@@ -106,31 +108,45 @@ class AutoInjectionTests: XCTestCase {
("testThatNoErrorThrownWhenOptionalPropertiesAreNotAutoInjected", testThatNoErrorThrownWhenOptionalPropertiesAreNotAutoInjected),
("testThatItResolvesTaggedAutoInjectedProperties", testThatItResolvesTaggedAutoInjectedProperties),
("testThatItPassesTagToAutoInjectedProperty", testThatItPassesTagToAutoInjectedProperty),
("testThatItDoesNotPassTagToAutoInjectedPropertyWithExplicitTag", testThatItDoesNotPassTagToAutoInjectedPropertyWithExplicitTag)
("testThatItDoesNotPassTagToAutoInjectedPropertyWithExplicitTag", testThatItDoesNotPassTagToAutoInjectedPropertyWithExplicitTag),
("testThatItAutoInjectsPropertyWithCollaboratingContainer", testThatItAutoInjectsPropertyWithCollaboratingContainer)
]
}
}()
func setUp() {
container.reset()
}
#else
override func setUp() {
container.reset()
}
#endif
func testThatItResolvesAutoInjectedDependencies() {
container.register(.ObjectGraph) { ServerImp() as Server }
container.register(.ObjectGraph) { ClientImp() as Client }
container.register { ServerImp() as Server }
container.register { ClientImp() as Client }
let client = try! container.resolve() as Client
let server = client.server
XCTAssertTrue(client === server?.client)
}
func testThatItResolvesInheritedDependencies() {
class ServerImp2: ServerImp {
var _client2 = InjectedWeak<Client>() { _ in
XCTAssertTrue(AutoInjectionTests.serverDidInjectCalled, "Inherited properties should be resolved first")
}
var client2: Client? { return _client2.value }
}
container.register { ServerImp2() as Server }
container.register { ClientImp() as Client }
//when
let client = try! container.resolve() as Client
let server = client.server as? ServerImp2
XCTAssertTrue(client === server?.client)
XCTAssertTrue(client === server?.client2)
}
func testThatItCanSetInjectedProperty() {
container.register(.ObjectGraph) { ServerImp() as Server }
container.register(.ObjectGraph) { ClientImp() as Client }
container.register { ServerImp() as Server }
container.register { ClientImp() as Client }
let client = (try! container.resolve() as Client) as! ClientImp
let server = client.server as! ServerImp
@@ -145,15 +161,15 @@ class AutoInjectionTests: XCTestCase {
}
func testThatItThrowsErrorIfFailsToAutoInjectDependency() {
container.register(.ObjectGraph) { ClientImp() as Client }
container.register { ClientImp() as Client }
AssertThrows(expression: try container.resolve() as Client)
}
func testThatItResolvesAutoInjectedSingletons() {
//given
container.register(.Singleton) { ServerImp() as Server }
container.register(.Singleton) { ClientImp() as Client }
container.register(.singleton) { ServerImp() as Server }
container.register(.singleton) { ClientImp() as Client }
//when
let sharedClient = try! container.resolve() as Client
@@ -172,34 +188,34 @@ class AutoInjectionTests: XCTestCase {
var serverBlockWasCalled = false
//given
container.register(.ObjectGraph) { ServerImp() as Server }
.resolveDependencies { (container, server) -> () in
container.register { ServerImp() as Server }
.resolvingProperties { (container, server) -> () in
serverBlockWasCalled = true
}
var clientBlockWasCalled = false
container.register(.ObjectGraph) { ClientImp() as Client }
.resolveDependencies { (container, client) -> () in
container.register { ClientImp() as Client }
.resolvingProperties { (container, client) -> () in
clientBlockWasCalled = true
}
//when
try! container.resolve() as Client
let _ = try! container.resolve() as Client
XCTAssertTrue(serverBlockWasCalled)
try! container.resolve() as Server
let _ = try! container.resolve() as Server
XCTAssertTrue(clientBlockWasCalled)
}
func testThatItReusesResolvedAutoInjectedInstances() {
//given
container.register(.ObjectGraph) { ServerImp() as Server }
.resolveDependencies { (container, server) -> () in
container.register { ServerImp() as Server }
.resolvingProperties { (container, server) -> () in
server.anotherClient = try! container.resolve() as Client
}
container.register(.ObjectGraph) { ClientImp() as Client }
.resolveDependencies { (container, client) -> () in
container.register { ClientImp() as Client }
.resolvingProperties { (container, client) -> () in
client.anotherServer = try! container.resolve() as Server
}
@@ -221,9 +237,9 @@ class AutoInjectionTests: XCTestCase {
func testThatItReusesAutoInjectedInstancesOnNextResolveOrAutoInjection() {
//given
container.register(.ObjectGraph) { Obj1() }
container.register(.ObjectGraph) { Obj2() }
container.register(.ObjectGraph) { Obj3(obj: try self.container.resolve()) }
container.register { Obj1() }
container.register { Obj2() }
container.register { Obj3(obj: try self.container.resolve()) }
//when
let obj2 = try! container.resolve() as Obj2
@@ -238,8 +254,8 @@ class AutoInjectionTests: XCTestCase {
func testThatThereIsNoRetainCycleBetweenAutoInjectedCircularDependencies() {
//given
container.register(.ObjectGraph) { ServerImp() as Server }
container.register(.ObjectGraph) { ClientImp() as Client }
container.register { ServerImp() as Server }
container.register { ClientImp() as Client }
//when
var client: Client? = try! container.resolve() as Client
@@ -262,11 +278,11 @@ class AutoInjectionTests: XCTestCase {
AutoInjectionTests.serverDidInjectCalled = false
//given
container.register(.ObjectGraph) { ServerImp() as Server }
container.register(.ObjectGraph) { ClientImp() as Client }
container.register { ServerImp() as Server }
container.register { ClientImp() as Client }
//when
try! container.resolve() as Client
let _ = try! container.resolve() as Client
//then
XCTAssertTrue(AutoInjectionTests.clientDidInjectCalled)
@@ -275,17 +291,17 @@ class AutoInjectionTests: XCTestCase {
func testThatNoErrorThrownWhenOptionalPropertiesAreNotAutoInjected() {
//given
container.register(.ObjectGraph) { ServerImp() as Server }
container.register(.ObjectGraph) { ClientImp() as Client }
container.register { ServerImp() as Server }
container.register { ClientImp() as Client }
AssertNoThrow(expression: try container.resolve() as Client, "Container should not throw error if failed to resolve optional auto-injected properties.")
}
func testThatItResolvesTaggedAutoInjectedProperties() {
//given
container.register(.ObjectGraph) { ServerImp() as Server }
container.register(tag: "tagged", .ObjectGraph) { ServerImp() as Server }
container.register(.ObjectGraph) { ClientImp() as Client }
container.register { ServerImp() as Server }
container.register(tag: "tagged") { ServerImp() as Server }
container.register { ClientImp() as Client }
//when
let client = try! container.resolve() as Client
@@ -302,9 +318,9 @@ class AutoInjectionTests: XCTestCase {
func testThatItPassesTagToAutoInjectedProperty() {
//given
container.register(.ObjectGraph) { ServerImp() as Server }
container.register(tag: "tagged", .ObjectGraph) { ServerImp() as Server }
container.register(.ObjectGraph) { ClientImp() as Client }
container.register { ServerImp() as Server }
container.register(tag: "tagged") { ServerImp() as Server }
container.register { ClientImp() as Client }
//when
let client = try! container.resolve(tag: "tagged") as Client
@@ -319,11 +335,11 @@ class AutoInjectionTests: XCTestCase {
func testThatItDoesNotPassTagToAutoInjectedPropertyWithExplicitTag() {
//given
container.register(.ObjectGraph) { ServerImp() as Server }
container.register(tag: "tagged", .ObjectGraph) { ServerImp() as Server }
container.register { ServerImp() as Server }
container.register(tag: "tagged") { ServerImp() as Server }
container.register(.ObjectGraph) { ClientImp() as Client }
.resolveDependencies { (container, client) -> () in
container.register { ClientImp() as Client }
.resolvingProperties { (container, client) -> () in
client.anotherServer = try! container.resolve() as Server
}
@@ -346,8 +362,8 @@ class AutoInjectionTests: XCTestCase {
func testThatItAutoInjectsPropertyWithCollaboratingContainer() {
let collaborator = DependencyContainer()
collaborator.register(.ObjectGraph) { ServerImp() as Server }
container.register(.ObjectGraph) { ClientImp() as Client }
collaborator.register { ServerImp() as Server }
container.register { ClientImp() as Client }
container.collaborate(with: collaborator)
collaborator.collaborate(with: container)
@@ -50,8 +50,7 @@ class AutoWiringTests: XCTestCase {
let container = DependencyContainer()
#if os(Linux)
static var allTests: [(String, AutoWiringTests -> () throws -> Void)] {
static var allTests = {
return [
("testThatItCanResolveWithAutoWiring", testThatItCanResolveWithAutoWiring),
("testThatItUsesAutoWireFactoryWithMostNumberOfArguments", testThatItUsesAutoWireFactoryWithMostNumberOfArguments),
@@ -71,23 +70,18 @@ class AutoWiringTests: XCTestCase {
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith6Arguments", testThatItUsesTagToResolveDependenciesWithAutoWiringWith6Arguments),
("testThatItCanAutoWireOptional", testThatItCanAutoWireOptional)
]
}
}()
func setUp() {
container.reset()
}
#else
override func setUp() {
container.reset()
}
#endif
func testThatItCanResolveWithAutoWiring() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register { ServiceImp1() as Service }
container.register { ServiceImp2() }
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
//when
let client = try! container.resolve() as AutoWiredClient
@@ -109,19 +103,19 @@ class AutoWiringTests: XCTestCase {
//given
//1 arg
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
//1 arg
container.register(.ObjectGraph) { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }
container.register { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }
//2 args
var factoryWithMostNumberOfArgumentsCalled = false
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolveDependencies { _ in
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolvingProperties { _ in
factoryWithMostNumberOfArgumentsCalled = true
}
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register { ServiceImp1() as Service }
container.register { ServiceImp2() }
//when
let _ = try! container.resolve() as AutoWiredClient
@@ -134,18 +128,18 @@ class AutoWiringTests: XCTestCase {
//given
//1 arg
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
//1 arg
container.register(.ObjectGraph) { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }
container.register { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register { ServiceImp1() as Service }
container.register { ServiceImp2() }
//when
AssertThrows(expression: try container.resolve() as AutoWiredClient) { error -> Bool in
switch error {
case let DipError.AutoWiringFailed(_, error):
if case DipError.AmbiguousDefinitions = error { return true }
case let DipError.autoWiringFailed(_, error):
if case DipError.ambiguousDefinitions = error { return true }
else { return false }
default: return false
}
@@ -156,24 +150,24 @@ class AutoWiringTests: XCTestCase {
//given
//1 arg
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
//1 arg
container.register(.ObjectGraph) { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }
container.register { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }
//2 args
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
//1 arg tagged
var taggedFactoryWithMostNumberOfArgumentsCalled = false
container.register(tag: "tag", .ObjectGraph) { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
//2 arg tagged
container.register(tag: "tag", .ObjectGraph) { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }.resolveDependencies { _ in
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }.resolvingProperties { _ in
taggedFactoryWithMostNumberOfArgumentsCalled = true
}
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register() { ServiceImp1() as Service }
container.register { ServiceImp2() }
//when
let _ = try! container.resolve(tag: "tag") as AutoWiredClient
@@ -187,15 +181,15 @@ class AutoWiringTests: XCTestCase {
//1 arg
var notTaggedFactoryWithMostNumberOfArgumentsCalled = false
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }.resolveDependencies {_ in
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }.resolvingProperties { _ in
notTaggedFactoryWithMostNumberOfArgumentsCalled = true
}
//1 arg tagged
container.register(tag: "tag", .ObjectGraph) { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register { ServiceImp1() as Service }
container.register { ServiceImp2() }
//when
let _ = try! container.resolve(tag: "other tag") as AutoWiredClient
@@ -206,36 +200,36 @@ class AutoWiringTests: XCTestCase {
func testThatItDoesNotTryToUseAutoWiringWhenCallingResolveWithArguments() {
//given
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
container.register { ServiceImp1() as Service }
container.register { ServiceImp2() }
//when
let service = try! container.resolve() as Service
AssertThrows(expression: try container.resolve(withArguments: service) as AutoWiredClient,
AssertThrows(expression: try container.resolve(arguments: service) as AutoWiredClient,
"Container should not use auto-wiring when resolving with runtime arguments")
}
func testThatItDoesNotUseAutoWiringWhenFailedToResolveLowLevelDependency() {
//given
container.register(.ObjectGraph) { AutoWiredClientImp() as AutoWiredClient }
.resolveDependencies { container, resolved in
container.register { AutoWiredClientImp() as AutoWiredClient }
.resolvingProperties { container, resolved in
resolved.service1 = try container.resolve() as Service
resolved.service2 = try container.resolve() as ServiceImp2
//simulate that something goes wrong on the way
throw DipError.DefinitionNotFound(key: DefinitionKey(protocolType: ServiceImp1.self, argumentsType: Any.self))
throw DipError.definitionNotFound(key: DefinitionKey(type: ServiceImp1.self, typeOfArguments: Any.self))
}
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolveDependencies { container, resolved in
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolvingProperties { container, resolved in
//auto-wiring should be performed only when definition for type to resolve is not found
//but not for any other type along the way in the graph
XCTFail("Auto-wiring should not be performed if instance was actually resolved.")
}
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register { ServiceImp1() as Service }
container.register { ServiceImp2() }
//then
AssertThrows(expression: try container.resolve() as AutoWiredClient,
@@ -245,13 +239,13 @@ class AutoWiringTests: XCTestCase {
func testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgain() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register { ServiceImp1() as Service }
container.register { ServiceImp2() }
var anotherInstance: AutoWiredClient?
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolveDependencies { container, _ in
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolvingProperties { container, _ in
if anotherInstance == nil {
anotherInstance = try! container.resolve() as AutoWiredClient
}
@@ -268,13 +262,13 @@ class AutoWiringTests: XCTestCase {
func testThatItReusesInstancesResolvedWithoutAutoWiringWhenUsingAutoWiringAgain() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register { ServiceImp1() as Service }
container.register { ServiceImp2() }
var anotherInstance: AutoWiredClient?
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolveDependencies { container, _ in
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolvingProperties { container, _ in
if anotherInstance == nil {
anotherInstance = try! container.resolve() as AutoWiredClient
}
@@ -283,7 +277,7 @@ class AutoWiringTests: XCTestCase {
//when
let service1 = try! container.resolve() as Service?
let service2 = try! container.resolve() as ServiceImp2
let resolved = try! container.resolve(withArguments: service1, service2) as AutoWiredClient
let resolved = try! container.resolve(arguments: service1, service2) as AutoWiredClient
//then
//when doing another auto-wiring during resolve we should reuse instance
@@ -293,13 +287,13 @@ class AutoWiringTests: XCTestCase {
func testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithTheSameTag() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register { ServiceImp1() as Service }
container.register { ServiceImp2() }
var anotherInstance: AutoWiredClient?
container.register(tag: "tag", .ObjectGraph) { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolveDependencies { container, _ in
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolvingProperties { container, _ in
if anotherInstance == nil {
anotherInstance = try! container.resolve(tag: "tag") as AutoWiredClient
}
@@ -313,16 +307,16 @@ class AutoWiringTests: XCTestCase {
XCTAssertTrue((resolved as! AutoWiredClientImp) === (anotherInstance as! AutoWiredClientImp))
}
func testThatItDoesNotReuseInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithNoTag() {
func testThatItDoesNotReuseInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithAnotherTag() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register { ServiceImp1() as Service }
container.register { ServiceImp2() }
var anotherInstance: AutoWiredClient?
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolveDependencies { container, _ in
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolvingProperties { container, _ in
if anotherInstance == nil {
anotherInstance = try! container.resolve() as AutoWiredClient
}
@@ -338,10 +332,10 @@ class AutoWiringTests: XCTestCase {
func testThatItUsesTagToResolveDependenciesWithAutoWiringWith1Argument() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(tag: "tag", .ObjectGraph) { ServiceImp2() as Service }
container.register { ServiceImp1() as Service }
container.register(tag: "tag") { ServiceImp2() as Service }
container.register(.ObjectGraph) { (dep1: Service) -> ServiceImp3 in
container.register { (dep1: Service) -> ServiceImp3 in
XCTAssertTrue(dep1 is ServiceImp2)
return ServiceImp3()
}
@@ -352,10 +346,10 @@ class AutoWiringTests: XCTestCase {
func testThatItUsesTagToResolveDependenciesWithAutoWiringWith2Arguments() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(tag: "tag", .ObjectGraph) { ServiceImp2() as Service }
container.register { ServiceImp1() as Service }
container.register(tag: "tag") { ServiceImp2() as Service }
container.register(.ObjectGraph) { (dep1: Service, dep2: Service) -> ServiceImp3 in
container.register { (dep1: Service, dep2: Service) -> ServiceImp3 in
XCTAssertTrue(dep1 is ServiceImp2)
XCTAssertTrue(dep2 is ServiceImp2)
return ServiceImp3()
@@ -367,10 +361,10 @@ class AutoWiringTests: XCTestCase {
func testThatItUsesTagToResolveDependenciesWithAutoWiringWith3Arguments() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(tag: "tag", .ObjectGraph) { ServiceImp2() as Service }
container.register { ServiceImp1() as Service }
container.register(tag: "tag") { ServiceImp2() as Service }
container.register(.ObjectGraph) { (dep1: Service, dep2: Service, dep3: Service) -> ServiceImp3 in
container.register { (dep1: Service, dep2: Service, dep3: Service) -> ServiceImp3 in
XCTAssertTrue(dep1 is ServiceImp2)
XCTAssertTrue(dep2 is ServiceImp2)
XCTAssertTrue(dep3 is ServiceImp2)
@@ -383,10 +377,10 @@ class AutoWiringTests: XCTestCase {
func testThatItUsesTagToResolveDependenciesWithAutoWiringWith4Arguments() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(tag: "tag", .ObjectGraph) { ServiceImp2() as Service }
container.register { ServiceImp1() as Service }
container.register(tag: "tag") { ServiceImp2() as Service }
container.register(.ObjectGraph) { (dep1: Service, dep2: Service, dep3: Service, dep4: Service) -> ServiceImp3 in
container.register { (dep1: Service, dep2: Service, dep3: Service, dep4: Service) -> ServiceImp3 in
XCTAssertTrue(dep1 is ServiceImp2)
XCTAssertTrue(dep2 is ServiceImp2)
XCTAssertTrue(dep3 is ServiceImp2)
@@ -400,10 +394,10 @@ class AutoWiringTests: XCTestCase {
func testThatItUsesTagToResolveDependenciesWithAutoWiringWith5Arguments() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(tag: "tag", .ObjectGraph) { ServiceImp2() as Service }
container.register { ServiceImp1() as Service }
container.register(tag: "tag") { ServiceImp2() as Service }
container.register(.ObjectGraph) { (dep1: Service, dep2: Service, dep3: Service, dep4: Service, dep5: Service) -> ServiceImp3 in
container.register { (dep1: Service, dep2: Service, dep3: Service, dep4: Service, dep5: Service) -> ServiceImp3 in
XCTAssertTrue(dep1 is ServiceImp2)
XCTAssertTrue(dep2 is ServiceImp2)
XCTAssertTrue(dep3 is ServiceImp2)
@@ -418,10 +412,10 @@ class AutoWiringTests: XCTestCase {
func testThatItUsesTagToResolveDependenciesWithAutoWiringWith6Arguments() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(tag: "tag", .ObjectGraph) { ServiceImp2() as Service }
container.register { ServiceImp1() as Service }
container.register(tag: "tag") { ServiceImp2() as Service }
container.register(.ObjectGraph) { (dep1: Service, dep2: Service, dep3: Service, dep4: Service, dep5: Service, dep6: Service) -> ServiceImp3 in
container.register { (dep1: Service, dep2: Service, dep3: Service, dep4: Service, dep5: Service, dep6: Service) -> ServiceImp3 in
XCTAssertTrue(dep1 is ServiceImp2)
XCTAssertTrue(dep2 is ServiceImp2)
XCTAssertTrue(dep3 is ServiceImp2)
@@ -437,9 +431,9 @@ class AutoWiringTests: XCTestCase {
func testThatItCanAutoWireOptional() {
//given
container.register(.ObjectGraph) { ServiceImp1() as Service }
container.register(.ObjectGraph) { ServiceImp2() }
container.register(.ObjectGraph) { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
container.register { ServiceImp1() as Service }
container.register { ServiceImp2() }
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
var resolved: AutoWiredClient?
//when
@@ -47,47 +47,41 @@ class ComponentScopeTests: XCTestCase {
let container = DependencyContainer()
#if os(Linux)
static var allTests: [(String, ComponentScopeTests -> () throws -> Void)] {
static var allTests = {
return [
("testThatPrototypeIsDefaultScope", testThatPrototypeIsDefaultScope),
("testThatSharedIsDefaultScope", testThatSharedIsDefaultScope),
("testThatScopeCanBeChanged", testThatScopeCanBeChanged),
("testThatItResolvesTypeAsNewInstanceForPrototypeScope", testThatItResolvesTypeAsNewInstanceForPrototypeScope),
("testThatItResolvesTypeAsNewInstanceForUniqueScope", testThatItResolvesTypeAsNewInstanceForUniqueScope),
("testThatItReusesInstanceForSingletonScope", testThatItReusesInstanceForSingletonScope),
("testThatSingletonIsNotReusedAcrossContainers", testThatSingletonIsNotReusedAcrossContainers),
("testThatSingletonIsReleasedWhenDefinitionIsRemoved", testThatSingletonIsReleasedWhenDefinitionIsRemoved),
("testThatSingletonIsReleasedWhenDefinitionIsOverridden", testThatSingletonIsReleasedWhenDefinitionIsOverridden),
("testThatSingletonIsReleasedWhenContainerIsReset", testThatSingletonIsReleasedWhenContainerIsReset),
("testThatItReusesInstanceInObjectGraphScopeDuringResolve", testThatItReusesInstanceInObjectGraphScopeDuringResolve),
("testThatItDoesNotReuseInstanceInObjectGraphScopeInNextResolve", testThatItDoesNotReuseInstanceInObjectGraphScopeInNextResolve),
("testThatItDoesNotReuseInstanceInObjectGraphScopeResolvedForNilTag", testThatItDoesNotReuseInstanceInObjectGraphScopeResolvedForNilTagWhenResolvingForAnotherTag),
("testThatItReusesInstanceInObjectGraphScopeResolvedForNilTag", testThatItReusesInstanceInObjectGraphScopeResolvedForNilTag),
("testThatItReusesInstanceInSharedScopeDuringResolve", testThatItReusesInstanceInSharedScopeDuringResolve),
("testThatItDoesNotReuseInstanceInSharedScopeInNextResolve", testThatItDoesNotReuseInstanceInSharedScopeInNextResolve),
("testThatItDoesNotReuseInstanceInSharedScopeResolvedForNilTag", testThatItDoesNotReuseInstanceInSharedScopeResolvedForNilTagWhenResolvingForAnotherTag),
("testThatItReusesInstanceInSharedScopeResolvedForNilTag", testThatItReusesInstanceInSharedScopeResolvedForNilTag),
("testThatItReusesResolvedInstanceWhenResolvingOptional", testThatItReusesResolvedInstanceWhenResolvingOptional),
("testThatItHoldsWeakReferenceToWeakSingletonInstance",
testThatItHoldsWeakReferenceToWeakSingletonInstance)
]
}
}()
func setUp() {
container.reset()
}
#else
override func setUp() {
container.reset()
}
#endif
func testThatPrototypeIsDefaultScope() {
func testThatSharedIsDefaultScope() {
let def = container.register { ServiceImp1() as Service }
XCTAssertEqual(def.scope, ComponentScope.Prototype)
XCTAssertEqual(def.scope, ComponentScope.shared)
}
func testThatScopeCanBeChanged() {
let def = container.register(.Singleton) { ServiceImp1() as Service }
XCTAssertEqual(def.scope, ComponentScope.Singleton)
let def = container.register(.singleton) { ServiceImp1() as Service }
XCTAssertEqual(def.scope, ComponentScope.singleton)
}
func testThatItResolvesTypeAsNewInstanceForPrototypeScope() {
func testThatItResolvesTypeAsNewInstanceForUniqueScope() {
//given
container.register { ServiceImp1() as Service }
@@ -100,7 +94,7 @@ class ComponentScopeTests: XCTestCase {
}
func testThatItReusesInstanceForSingletonScope() {
func test(scope: ComponentScope) {
func test(_ scope: ComponentScope, line: UInt = #line) {
//given
container.register(scope) { ServiceImp1() as Service }
@@ -109,94 +103,99 @@ class ComponentScopeTests: XCTestCase {
let service2 = try! container.resolve() as Service
//then
XCTAssertTrue(service1 === service2)
XCTAssertTrue(service1 === service2, line: line)
}
test(.Singleton)
test(.EagerSingleton)
test(.singleton)
test(.weakSingleton)
test(.eagerSingleton)
}
func testThatSingletonIsNotReusedAcrossContainers() {
func test(scope: ComponentScope) {
func test(_ scope: ComponentScope, line: UInt = #line) {
//given
let def = container.register(.Singleton) { ServiceImp1() as Service }
let def = container.register(scope) { ServiceImp1() as Service }
let secondContainer = DependencyContainer()
secondContainer.register(def, forTag: nil)
secondContainer.register(def, tag: nil)
//when
let service1 = try! container.resolve() as Service
let service2 = try! secondContainer.resolve() as Service
//then
XCTAssertTrue(service1 !== service2, "Singleton instances should not be reused across containers")
XCTAssertTrue(service1 !== service2, "Singleton instances should not be reused across containers", line: line)
}
test(.Singleton)
test(.EagerSingleton)
test(.singleton)
test(.weakSingleton)
test(.eagerSingleton)
}
func testThatSingletonIsReleasedWhenDefinitionIsRemoved() {
func test(scope: ComponentScope) {
func test(_ scope: ComponentScope, line: UInt = #line) {
//given
let def = container.register(.Singleton) { ServiceImp1() as Service }
let def = container.register(scope) { ServiceImp1() as Service }
let service1 = try! container.resolve() as Service
//when
container.remove(def, forTag: nil)
container.register(def, forTag: nil)
container.remove(def, tag: nil)
container.register(def, tag: nil)
//then
let service2 = try! container.resolve() as Service
XCTAssertTrue(service1 !== service2, "Singleton instances should be released when definition is removed from the container")
XCTAssertTrue(service1 !== service2, "Singleton instances should be released when definition is removed from the container", line: line)
}
test(.Singleton)
test(.EagerSingleton)
test(.singleton)
test(.weakSingleton)
test(.eagerSingleton)
}
func testThatSingletonIsReleasedWhenDefinitionIsOverridden() {
func test(scope: ComponentScope) {
func test(_ scope: ComponentScope, line: UInt = #line) {
//given
let def = container.register(.Singleton) { ServiceImp1() as Service }
let def = container.register(scope) { ServiceImp1() as Service }
let service1 = try! container.resolve() as Service
//when
container.register(def, forTag: nil)
container.register(def, tag: nil)
//then
let service2 = try! container.resolve() as Service
XCTAssertTrue(service1 !== service2, "Singleton instances should be released when definition is overridden")
XCTAssertTrue(service1 !== service2, "Singleton instances should be released when definition is overridden", line: line)
}
test(.Singleton)
test(.EagerSingleton)
test(.singleton)
test(.weakSingleton)
test(.eagerSingleton)
}
func testThatSingletonIsReleasedWhenContainerIsReset() {
func test(scope: ComponentScope) {
func test(_ scope: ComponentScope, line: UInt = #line) {
//given
let def = container.register(.Singleton) { ServiceImp1() as Service }
let def = container.register(scope) { ServiceImp1() as Service }
let service1 = try! container.resolve() as Service
//when
container.reset()
container.register(def, forTag: nil)
container.register(def, tag: nil)
//then
let service2 = try! container.resolve() as Service
XCTAssertTrue(service1 !== service2, "Singleton instances should be released when container is reset")
XCTAssertTrue(service1 !== service2, "Singleton instances should be released when container is reset", line: line)
}
test(.Singleton)
test(.EagerSingleton)
test(.singleton)
test(.weakSingleton)
test(.eagerSingleton)
}
func testThatItReusesInstanceInObjectGraphScopeDuringResolve() {
func testThatItReusesInstanceInSharedScopeDuringResolve() {
//given
container.register(.ObjectGraph) { Client(server: try self.container.resolve()) as Client }
container.register { Client(server: try self.container.resolve()) as Client }
container.register(.ObjectGraph) { Server() as Server }
.resolveDependencies { container, server in
container.register { Server() as Server }
.resolvingProperties { container, server in
server.client = try container.resolve() as Client
}
@@ -208,11 +207,11 @@ class ComponentScopeTests: XCTestCase {
XCTAssertTrue(server.client === client)
}
func testThatItDoesNotReuseInstanceInObjectGraphScopeInNextResolve() {
func testThatItDoesNotReuseInstanceInSharedScopeInNextResolve() {
//given
container.register(.ObjectGraph) { Client(server: try self.container.resolve()) as Client }
container.register(.ObjectGraph) { Server() as Server }
.resolveDependencies { container, server in
container.register { Client(server: try self.container.resolve()) as Client }
container.register { Server() as Server }
.resolvingProperties { container, server in
server.client = try container.resolve() as Client
}
@@ -228,18 +227,18 @@ class ComponentScopeTests: XCTestCase {
XCTAssertFalse(client === anotherClient)
}
func testThatItDoesNotReuseInstanceInObjectGraphScopeResolvedForNilTagWhenResolvingForAnotherTag() {
func testThatItDoesNotReuseInstanceInSharedScopeResolvedForNilTagWhenResolvingForAnotherTag() {
//given
var service2: Service?
container.register(.ObjectGraph) { ServiceImp1() as Service }
.resolveDependencies { (c, _) in
container.register { ServiceImp1() as Service }
.resolvingProperties { (c, _) in
//when service1 is resolved using this definition due to fallback to nil tag
service2 = try c.resolve(tag: "service") as Service
//then we don't want every next resolve of service for other tags to reuse it
XCTAssertTrue(service2 is ServiceImp2)
}
container.register(tag: "service", .ObjectGraph) { ServiceImp2() as Service}
container.register(tag: "service") { ServiceImp2() as Service}
//when
let service1 = try! container.resolve(tag: "tag") as Service
@@ -248,11 +247,11 @@ class ComponentScopeTests: XCTestCase {
XCTAssertTrue(service1 is ServiceImp1)
}
func testThatItReusesInstanceInObjectGraphScopeResolvedForNilTag() {
func testThatItReusesInstanceInSharedScopeResolvedForNilTag() {
//given
var service2: Service?
container.register(.ObjectGraph) { ServiceImp1() as Service }
.resolveDependencies { (c, service1) in
container.register { ServiceImp1() as Service }
.resolvingProperties { (c, service1) in
guard service2 == nil else { return }
//when service1 is resolved using this definition due to fallback to nil tag
@@ -274,17 +273,17 @@ class ComponentScopeTests: XCTestCase {
//given
var eagerSingletonResolved = false
container.register(tag: "eager", .EagerSingleton) { ServiceImp1() as Service }
.resolveDependencies { container, service in eagerSingletonResolved = true }
container.register(.eagerSingleton, tag: "eager") { ServiceImp1() as Service }
.resolvingProperties { container, service in eagerSingletonResolved = true }
container.register(tag: "singleton", .Singleton) { ServiceImp1() as Service }
.resolveDependencies { container, service in XCTFail() }
container.register(.singleton, tag: "singleton") { ServiceImp1() as Service }
.resolvingProperties { container, service in XCTFail() }
container.register(tag: "prototype", .Prototype) { ServiceImp1() as Service }
.resolveDependencies { container, service in XCTFail() }
container.register(.unique, tag: "prototype") { ServiceImp1() as Service }
.resolvingProperties { container, service in XCTFail() }
container.register(tag: "graph", .ObjectGraph) { ServiceImp1() as Service }
.resolveDependencies { container, service in XCTFail() }
container.register(.shared, tag: "graph") { ServiceImp1() as Service }
.resolvingProperties { container, service in XCTFail() }
//when
try! container.bootstrap()
@@ -305,8 +304,8 @@ class ComponentScopeTests: XCTestCase {
var anyOtherService: Any!
var anyImpOtherService: Any!
container.register(.ObjectGraph) { ServiceImp1() as Service }
.resolveDependencies { container, service in
container.register { ServiceImp1() as Service }
.resolvingProperties { container, service in
otherService = try! container.resolve() as Service?
impOtherService = try! container.resolve() as Service!
anyOtherService = try! container.resolve((Service?).self)
@@ -322,7 +321,7 @@ class ComponentScopeTests: XCTestCase {
func testThatItHoldsWeakReferenceToWeakSingletonInstance() {
//given
container.register(.WeakSingleton) { ServiceImp1() as Service }
container.register(.weakSingleton) { ServiceImp1() as Service }
var strongSingleton: Service? = try! container.resolve() as Service
weak var weakSingleton = try! container.resolve() as Service
@@ -335,5 +334,29 @@ class ComponentScopeTests: XCTestCase {
//then
XCTAssertNil(weakSingleton)
}
func testThatCollaboratingContainersReuseSingletonsResolvedByAnotherContainer() {
func test(_ scope: ComponentScope, line: UInt = #line) {
let container1 = DependencyContainer()
container1.register(scope) { ServiceImp1() as Service }
let container2 = DependencyContainer()
container1.collaborate(with: container2)
container2.collaborate(with: container1)
try! container1.bootstrap()
try! container2.bootstrap()
let service1 = try! container1.resolve() as Service
let service2 = try! container2.resolve() as Service
XCTAssertTrue(service1 === service2, "\(scope) should be reused when first resolved from another container", line: line)
}
test(.singleton)
test(.weakSingleton)
test(.eagerSingleton)
}
}
@@ -39,8 +39,7 @@ class ContextTests: XCTestCase {
let container = DependencyContainer()
#if os(Linux)
static var allTests: [(String, ContextTests -> () throws -> Void)] {
static var allTests = {
return [
("testThatContextStoresCurrentlyResolvedType", testThatContextStoresCurrentlyResolvedType),
("testThatContextStoresInjectedInType", testThatContextStoresInjectedInType),
@@ -48,26 +47,23 @@ class ContextTests: XCTestCase {
("testThatContextStoresTheTagPassedToResolveWhenAutoInjecting", testThatContextStoresTheTagPassedToResolveWhenAutoInjecting),
("testThatContextStoresTheTagPassedToResolveWhenAutoWiring", testThatContextStoresTheTagPassedToResolveWhenAutoWiring),
("testThatContextDoesNotOverrideNilTagPassedToResolve", testThatContextDoesNotOverrideNilTagPassedToResolve),
("testThatContextStoresNameOfAutoInjectedProperty", testThatContextStoresNameOfAutoInjectedProperty)
("testThatContextStoresNameOfAutoInjectedProperty", testThatContextStoresNameOfAutoInjectedProperty),
("testThatItDoesNotSetInjectedInTypeWhenResolvingWithCollaboration", testThatItDoesNotSetInjectedInTypeWhenResolvingWithCollaboration),
("testThatContextIsPreservedWhenResolvingWithCollaboration", testThatContextIsPreservedWhenResolvingWithCollaboration)
]
}
}()
func setUp() {
container.reset()
}
#else
override func setUp() {
container.reset()
container.register { ServiceImp2() }
}
#endif
func testThatContextStoresCurrentlyResolvedType() {
container.register { () -> Service in
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolveDependencies { _ in
}.resolvingProperties { _ in
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
}
@@ -75,7 +71,7 @@ class ContextTests: XCTestCase {
container.register { () -> ServiceImp1 in
XCTAssertTrue(self.container.context.resolvingType == ServiceImp1.self)
return ServiceImp1()
}.resolveDependencies { _ in
}.resolvingProperties { _ in
XCTAssertTrue(self.container.context.resolvingType == ServiceImp1.self)
}
@@ -87,7 +83,7 @@ class ContextTests: XCTestCase {
XCTAssertNil(self.container.context.injectedInType)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolveDependencies { _ in
}.resolvingProperties { _ in
XCTAssertNil(self.container.context.injectedInType)
let _ = try self.container.resolve() as ServiceImp1
}
@@ -95,7 +91,7 @@ class ContextTests: XCTestCase {
container.register { () -> ServiceImp1 in
XCTAssertTrue(self.container.context.injectedInType == Service.self)
return ServiceImp1()
}.resolveDependencies { _ in
}.resolvingProperties { _ in
XCTAssertTrue(self.container.context.injectedInType == Service.self)
}
@@ -108,7 +104,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve(tag: "otherTag") as ServiceImp1
return ServiceImp1() as Service
}.resolveDependencies { _ in
}.resolvingProperties { _ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve(tag: "otherTag") as ServiceImp1
@@ -118,7 +114,7 @@ class ContextTests: XCTestCase {
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("otherTag") ~= self.container.context.tag!)
return ServiceImp1()
}.resolveDependencies { _ in
}.resolvingProperties { _ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("otherTag") ~= self.container.context.tag!)
}
@@ -130,7 +126,7 @@ class ContextTests: XCTestCase {
container.register { ServiceImp1() as Service }
container.register { ServiceImp1() }
container.register() { () -> ServiceImp2 in
container.register { () -> ServiceImp2 in
if self.container.context.injectedInProperty == "injectedNilTag" {
XCTAssertNil(self.container.context.tag)
}
@@ -139,7 +135,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(DependencyContainer.Tag.String("injectedTag") ~= self.container.context.tag!)
}
return ServiceImp2()
}.resolveDependencies { _ in
}.resolvingProperties { _ in
if self.container.context.injectedInProperty == "injectedNilTag" {
XCTAssertNil(self.container.context.tag)
}
@@ -153,7 +149,7 @@ class ContextTests: XCTestCase {
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
return ServiceImp2()
}.resolveDependencies { _ in
}.resolvingProperties { _ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
}
@@ -164,14 +160,14 @@ class ContextTests: XCTestCase {
func testThatContextStoresTheTagPassedToResolveWhenAutoWiring() {
container.register { (_: ServiceImp1) -> Service in
return ServiceImp1() as Service
}.resolveDependencies { _ in
}.resolvingProperties { _ in
}
container.register { () -> ServiceImp1 in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
return ServiceImp1()
}.resolveDependencies { _ in
}.resolvingProperties { _ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
}
@@ -185,7 +181,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolveDependencies { _ in
}.resolvingProperties { _ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve() as ServiceImp1
@@ -194,7 +190,7 @@ class ContextTests: XCTestCase {
container.register { () -> ServiceImp1 in
XCTAssertNil(self.container.context.tag)
return ServiceImp1()
}.resolveDependencies { _ in
}.resolvingProperties { _ in
XCTAssertNil(self.container.context.tag)
}
@@ -207,11 +203,11 @@ class ContextTests: XCTestCase {
let names = ["injected", "injectedWeak", "taggedInjected", "taggedInjectedWeak", "injectedNilTag"]
container.register() { () -> ServiceImp2 in
container.register { () -> ServiceImp2 in
XCTAssertNotNil(self.container.context.injectedInProperty)
XCTAssertTrue(names.contains(self.container.context.injectedInProperty!))
return ServiceImp2()
}.resolveDependencies { _ in
}.resolvingProperties { _ in
XCTAssertNotNil(self.container.context.injectedInProperty)
XCTAssertTrue(names.contains(self.container.context.injectedInProperty!))
}
@@ -219,4 +215,47 @@ class ContextTests: XCTestCase {
let _ = try! container.resolve() as Service
}
func testThatItDoesNotSetInjectedInTypeWhenResolvingWithCollaboration() {
let collaborator = DependencyContainer()
collaborator.register { () -> ServiceImp1 in
unowned let collaborator = collaborator
XCTAssertNil(collaborator.context.injectedInType)
return ServiceImp1()
}.resolvingProperties { collaborator, _ in
XCTAssertNil(collaborator.context.injectedInType)
}
container.collaborate(with: collaborator)
collaborator.collaborate(with: container)
let _ = try! container.resolve() as ServiceImp1
}
func testThatContextIsPreservedWhenResolvingWithCollaboration() {
let collaborator = DependencyContainer()
container.register { () -> Service in
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolvingProperties { _ in
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
}
collaborator.register { () -> ServiceImp1 in
XCTAssertTrue(collaborator.context.resolvingType == ServiceImp1.self)
return ServiceImp1()
}.resolvingProperties { _ in
XCTAssertTrue(collaborator.context.resolvingType == ServiceImp1.self)
}
container.collaborate(with: collaborator)
collaborator.collaborate(with: container)
let _ = try! container.resolve() as Service
collaborator.reset()
}
}
@@ -36,8 +36,7 @@ class DefinitionTests: XCTestCase {
let tag1 = DependencyContainer.Tag.String("tag1")
let tag2 = DependencyContainer.Tag.String("tag2")
#if os(Linux)
static var allTests: [(String, DefinitionTests -> () throws -> Void)] {
static var allTests = {
return [
("testThatDefinitionKeyIsEqualBy_Type_Factory_Tag", testThatDefinitionKeyIsEqualBy_Type_Factory_Tag),
("testThatDefinitionKeysWithDifferentTypesAreNotEqual", testThatDefinitionKeysWithDifferentTypesAreNotEqual),
@@ -47,36 +46,35 @@ class DefinitionTests: XCTestCase {
("testThatResolveDependenciesBlockIsNotCalledWhenPassedWrongInstance", testThatResolveDependenciesBlockIsNotCalledWhenPassedWrongInstance),
("testThatItRegisteresOptionalTypesAsForwardedTypes", testThatItRegisteresOptionalTypesAsForwardedTypes)
]
}
#endif
}()
func testThatDefinitionKeyIsEqualBy_Type_Factory_Tag() {
let equalKey1 = DefinitionKey(protocolType: Service.self, argumentsType: F1.self, associatedTag: tag1)
let equalKey2 = DefinitionKey(protocolType: Service.self, argumentsType: F1.self, associatedTag: tag1)
let equalKey1 = DefinitionKey(type: Service.self, typeOfArguments: F1.self, tag: tag1)
let equalKey2 = DefinitionKey(type: Service.self, typeOfArguments: F1.self, tag: tag1)
XCTAssertEqual(equalKey1, equalKey2)
XCTAssertEqual(equalKey1.hashValue, equalKey2.hashValue)
}
func testThatDefinitionKeysWithDifferentTypesAreNotEqual() {
let keyWithDifferentType1 = DefinitionKey(protocolType: Service.self, argumentsType: F1.self, associatedTag: nil)
let keyWithDifferentType2 = DefinitionKey(protocolType: AnyObject.self, argumentsType: F1.self, associatedTag: nil)
let keyWithDifferentType1 = DefinitionKey(type: Service.self, typeOfArguments: F1.self, tag: nil)
let keyWithDifferentType2 = DefinitionKey(type: AnyObject.self, typeOfArguments: F1.self, tag: nil)
XCTAssertNotEqual(keyWithDifferentType1, keyWithDifferentType2)
XCTAssertNotEqual(keyWithDifferentType1.hashValue, keyWithDifferentType2.hashValue)
}
func testThatDefinitionKeysWithDifferentFactoriesAreNotEqual() {
let keyWithDifferentFactory1 = DefinitionKey(protocolType: Service.self, argumentsType: F1.self, associatedTag: nil)
let keyWithDifferentFactory2 = DefinitionKey(protocolType: Service.self, argumentsType: F2.self, associatedTag: nil)
let keyWithDifferentFactory1 = DefinitionKey(type: Service.self, typeOfArguments: F1.self, tag: nil)
let keyWithDifferentFactory2 = DefinitionKey(type: Service.self, typeOfArguments: F2.self, tag: nil)
XCTAssertNotEqual(keyWithDifferentFactory1, keyWithDifferentFactory2)
XCTAssertNotEqual(keyWithDifferentFactory1.hashValue, keyWithDifferentFactory2.hashValue)
}
func testThatDefinitionKeysWithDifferentTagsAreNotEqual() {
let keyWithDifferentTag1 = DefinitionKey(protocolType: Service.self, argumentsType: F1.self, associatedTag: tag1)
let keyWithDifferentTag2 = DefinitionKey(protocolType: Service.self, argumentsType: F1.self, associatedTag: tag2)
let keyWithDifferentTag1 = DefinitionKey(type: Service.self, typeOfArguments: F1.self, tag: tag1)
let keyWithDifferentTag2 = DefinitionKey(type: Service.self, typeOfArguments: F1.self, tag: tag2)
XCTAssertNotEqual(keyWithDifferentTag1, keyWithDifferentTag2)
XCTAssertNotEqual(keyWithDifferentTag1.hashValue, keyWithDifferentTag2.hashValue)
@@ -86,13 +84,13 @@ class DefinitionTests: XCTestCase {
var blockCalled = false
//given
let def = DefinitionOf<Service, () -> Service>(scope: .Prototype) { ServiceImp() as Service }
.resolveDependencies { container, service in
let def = Definition<Service, ()>(scope: .unique) { ServiceImp() as Service }
.resolvingProperties { container, service in
blockCalled = true
}
//when
try! def.resolveDependenciesOf(ServiceImp(), withContainer: DependencyContainer())
try! def.resolveProperties(of: ServiceImp(), container: DependencyContainer())
//then
XCTAssertTrue(blockCalled)
@@ -102,23 +100,23 @@ class DefinitionTests: XCTestCase {
var blockCalled = false
//given
let def = DefinitionOf<Service, () -> Service>(scope: .Prototype) { ServiceImp() as Service }
.resolveDependencies { container, service in
let def = Definition<Service, ()>(scope: .unique) { ServiceImp() as Service }
.resolvingProperties { container, service in
blockCalled = true
}
//when
try! def.resolveDependenciesOf(String(), withContainer: DependencyContainer())
try! def.resolveProperties(of: String(), container: DependencyContainer())
//then
XCTAssertFalse(blockCalled)
}
func testThatItRegisteresOptionalTypesAsForwardedTypes() {
let def = DefinitionOf<Service, () -> Service>(scope: .Prototype) { ServiceImp() as Service }
let def = Definition<Service, ()>(scope: .unique) { ServiceImp() as Service }
XCTAssertTrue(def.implementingTypes.contains({ $0 == Service?.self }))
XCTAssertTrue(def.implementingTypes.contains({ $0 == Service!.self }))
XCTAssertTrue(def.implementingTypes.contains(where: { $0 == Service?.self }))
XCTAssertTrue(def.implementingTypes.contains(where: { $0 == Service!.self }))
}
}
@@ -30,10 +30,10 @@ private class ServiceImp1: Service { }
private class ServiceImp2: Service { }
private protocol Server: class {
weak var client: Client? { get }
weak var client: Client! { get }
}
private protocol Client: class {
var server: Server? { get }
var server: Server! { get }
}
class ResolvableService: Service, Resolvable {
@@ -49,9 +49,9 @@ class DipTests: XCTestCase {
let container = DependencyContainer()
#if os(Linux)
static var allTests: [(String, DipTests -> () throws -> Void)] {
static var allTests = {
return [
("testThatCreatingContainerWithConfigBlockDoesNotCreateRetainCycle", testThatCreatingContainerWithConfigBlockDoesNotCreateRetainCycle),
("testThatItResolvesInstanceRegisteredWithoutTag", testThatItResolvesInstanceRegisteredWithoutTag),
("testThatItResolvesInstanceRegisteredWithTag", testThatItResolvesInstanceRegisteredWithTag),
("testThatItResolvesDifferentInstancesRegisteredForDifferentTags", testThatItResolvesDifferentInstancesRegisteredForDifferentTags),
@@ -64,19 +64,43 @@ class DipTests: XCTestCase {
("testThatItThrowsErrorIfFailsToResolveDependency", testThatItThrowsErrorIfFailsToResolveDependency),
("testThatItCallsDidResolveDependenciesOnResolvableIntance", testThatItCallsDidResolveDependenciesOnResolvableIntance),
("testThatItCallsDidResolveDependenciesInReverseOrder", testThatItCallsDidResolveDependenciesInReverseOrder),
("testItCallsResolveDependenciesOnResolableInstance", testItCallsResolveDependenciesOnResolableInstance),
("testThatItResolvesCircularDependencies", testThatItResolvesCircularDependencies),
("testContainerCollaborators", testContainerCollaborators)
("testThatItCanResolveUsingContainersCollaboration", testThatItCanResolveUsingContainersCollaboration),
("testThatCollaboratingWithSelfIsIgnored", testThatCollaboratingWithSelfIsIgnored),
("testThatCollaboratingContainersAreWeakReferences", testThatCollaboratingContainersAreWeakReferences),
("testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer", testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer),
]
}
}()
func setUp() {
container.reset()
}
#else
override func setUp() {
container.reset()
}
#endif
func testThatCreatingContainerWithConfigBlockDoesNotCreateRetainCycle() {
var container: DependencyContainer! = DependencyContainer() { container in
//compiler crashes if you try to capture container in capture list
//so instead we capture it in a variable
unowned let container = container
container.register { ServiceImp1() }
container.register { (_: ServiceImp1)->Service in
//referencing container in factory
let _ = container
return ServiceImp1() as Service
}.resolvingProperties { container, _ in
//when container is passed as argument there will be no retain cycle
let _ = container
}
}
let _ = try! container.resolve() as Service
weak var weakContainer = container
container = nil
XCTAssertNil(weakContainer)
}
func testThatItResolvesInstanceRegisteredWithoutTag() {
//given
@@ -191,19 +215,19 @@ class DipTests: XCTestCase {
func testThatItCallsResolveDependenciesOnDefinition() {
//given
var resolveDependenciesCalled = false
container.register { ServiceImp1() as Service }.resolveDependencies { (c, s) in
container.register { ServiceImp1() as Service }.resolvingProperties { (c, s) in
resolveDependenciesCalled = true
}
//when
try! container.resolve() as Service
let _ = try! container.resolve() as Service
//then
XCTAssertTrue(resolveDependenciesCalled)
resolveDependenciesCalled = false
//and when
try! container.resolve(Service.self)
let _ = try! container.resolve(Service.self)
//then
XCTAssertTrue(resolveDependenciesCalled)
@@ -211,7 +235,7 @@ class DipTests: XCTestCase {
resolveDependenciesCalled = false
//and when
try! container.resolve((Service?).self)
let _ = try! container.resolve((Service?).self)
//then
XCTAssertTrue(resolveDependenciesCalled)
@@ -219,7 +243,7 @@ class DipTests: XCTestCase {
resolveDependenciesCalled = false
//and when
try! container.resolve((Service!).self)
let _ = try! container.resolve((Service!).self)
//then
XCTAssertTrue(resolveDependenciesCalled)
@@ -231,10 +255,10 @@ class DipTests: XCTestCase {
//when
AssertThrows(expression: try container.resolve() as Service) { error in
guard case let DipError.DefinitionNotFound(key) = error else { return false }
guard case let DipError.definitionNotFound(key) = error else { return false }
//then
let expectedKey = DefinitionKey(protocolType: Service.self, argumentsType: Void.self, associatedTag: nil)
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: Void.self, tag: nil)
XCTAssertEqual(key, expectedKey)
return true
@@ -242,10 +266,10 @@ class DipTests: XCTestCase {
//and when
AssertThrows(expression: try container.resolve(Service.self)) { error in
guard case let DipError.DefinitionNotFound(key) = error else { return false }
guard case let DipError.definitionNotFound(key) = error else { return false }
//then
let expectedKey = DefinitionKey(protocolType: Service.self, argumentsType: Void.self, associatedTag: nil)
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: Void.self, tag: nil)
XCTAssertEqual(key, expectedKey)
return true
@@ -258,10 +282,10 @@ class DipTests: XCTestCase {
//when
AssertThrows(expression: try container.resolve(tag: "other tag") as Service) { error in
guard case let DipError.DefinitionNotFound(key) = error else { return false }
guard case let DipError.definitionNotFound(key) = error else { return false }
//then
let expectedKey = DefinitionKey(protocolType: Service.self, argumentsType: Void.self, associatedTag: "other tag")
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: Void.self, tag: "other tag")
XCTAssertEqual(key, expectedKey)
return true
@@ -269,10 +293,10 @@ class DipTests: XCTestCase {
//and when
AssertThrows(expression: try container.resolve(Service.self, tag: "other tag")) { error in
guard case let DipError.DefinitionNotFound(key) = error else { return false }
guard case let DipError.definitionNotFound(key) = error else { return false }
//then
let expectedKey = DefinitionKey(protocolType: Service.self, argumentsType: Void.self, associatedTag: "other tag")
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: Void.self, tag: "other tag")
XCTAssertEqual(key, expectedKey)
return true
@@ -284,22 +308,22 @@ class DipTests: XCTestCase {
container.register { ServiceImp1() as Service }
//when
AssertThrows(expression: try container.resolve(withArguments: "some string") as Service) { error in
guard case let DipError.DefinitionNotFound(key) = error else { return false }
AssertThrows(expression: try container.resolve(arguments: "some string") as Service) { error in
guard case let DipError.definitionNotFound(key) = error else { return false }
//then
let expectedKey = DefinitionKey(protocolType: Service.self, argumentsType: String.self, associatedTag: nil)
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: String.self, tag: nil)
XCTAssertEqual(key, expectedKey)
return true
}
//and when
AssertThrows(expression: try container.resolve(Service.self, withArguments: "some string")) { error in
guard case let DipError.DefinitionNotFound(key) = error else { return false }
AssertThrows(expression: try container.resolve(Service.self, arguments: "some string")) { error in
guard case let DipError.definitionNotFound(key) = error else { return false }
//then
let expectedKey = DefinitionKey(protocolType: Service.self, argumentsType: String.self, associatedTag: nil)
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: String.self, tag: nil)
XCTAssertEqual(key, expectedKey)
return true
@@ -308,14 +332,14 @@ class DipTests: XCTestCase {
func testThatItThrowsErrorIfConstructorThrows() {
//given
let failedKey = DefinitionKey(protocolType: Any.self, argumentsType: Any.self)
let expectedError = DipError.DefinitionNotFound(key: failedKey)
let failedKey = DefinitionKey(type: Any.self, typeOfArguments: Any.self)
let expectedError = DipError.definitionNotFound(key: failedKey)
container.register { () throws -> Service in throw expectedError }
//when
AssertThrows(expression: try container.resolve() as Service) { error in
switch error {
case let DipError.DefinitionNotFound(key) where key == failedKey: return true
case let DipError.definitionNotFound(key) where key == failedKey: return true
default: return false
}
}
@@ -323,7 +347,7 @@ class DipTests: XCTestCase {
//and when
AssertThrows(expression: try container.resolve(Service.self)) { error in
switch error {
case let DipError.DefinitionNotFound(key) where key == failedKey: return true
case let DipError.definitionNotFound(key) where key == failedKey: return true
default: return false
}
}
@@ -331,10 +355,10 @@ class DipTests: XCTestCase {
func testThatItThrowsErrorIfFailsToResolveDependency() {
//given
let failedKey = DefinitionKey(protocolType: Any.self, argumentsType: Any.self)
let expectedError = DipError.DefinitionNotFound(key: failedKey)
let failedKey = DefinitionKey(type: Any.self, typeOfArguments: Any.self)
let expectedError = DipError.definitionNotFound(key: failedKey)
container.register { ServiceImp1() as Service }
.resolveDependencies { container, service in
.resolvingProperties { container, service in
//simulate throwing error when resolving dependency
throw expectedError
}
@@ -342,7 +366,7 @@ class DipTests: XCTestCase {
//when
AssertThrows(expression: try container.resolve() as Service) { error in
switch error {
case let DipError.DefinitionNotFound(key) where key == failedKey: return true
case let DipError.definitionNotFound(key) where key == failedKey: return true
default: return false
}
}
@@ -350,7 +374,7 @@ class DipTests: XCTestCase {
//and when
AssertThrows(expression: try container.resolve(Service.self)) { error in
switch error {
case let DipError.DefinitionNotFound(key) where key == failedKey: return true
case let DipError.definitionNotFound(key) where key == failedKey: return true
default: return false
}
}
@@ -359,19 +383,19 @@ class DipTests: XCTestCase {
func testThatItCallsDidResolveDependenciesOnResolvableIntance() {
//given
container.register { ResolvableService() as Service }
.resolveDependencies { _, service in
.resolvingProperties { _, service in
XCTAssertFalse((service as! ResolvableService).didResolveDependenciesCalled, "didResolveDependencies should not be called yet")
return
}
container.register(tag: "graph", .ObjectGraph) { ResolvableService() as Service }
.resolveDependencies { _, service in
container.register(tag: "graph") { ResolvableService() as Service }
.resolvingProperties { _, service in
XCTAssertFalse((service as! ResolvableService).didResolveDependenciesCalled, "didResolveDependencies should not be called yet")
return
}
container.register(tag: "singleton", .Singleton) { ResolvableService() as Service }
.resolveDependencies { _, service in
container.register(.singleton, tag: "singleton") { ResolvableService() as Service }
.resolvingProperties { _, service in
XCTAssertFalse((service as! ResolvableService).didResolveDependenciesCalled, "didResolveDependencies should not be called yet")
return
}
@@ -410,7 +434,7 @@ class DipTests: XCTestCase {
var resolveDependenciesCalled = false
var service2: Service!
container.register { ResolvableService() as Service }
.resolveDependencies { _, service in
.resolvingProperties { _, service in
if !resolveDependenciesCalled {
resolveDependenciesCalled = true
service2 = try self.container.resolve() as Service
@@ -426,11 +450,41 @@ class DipTests: XCTestCase {
XCTAssertTrue(ResolvableService.resolved.last === service1)
}
func testItCallsResolveDependenciesOnResolableInstance() {
class Class: Resolvable {
var resolveDependenciesCalled = false
func resolveDependencies(_ container: DependencyContainer) {
resolveDependenciesCalled = true
}
}
class SubClass: Class {
override func resolveDependencies(_ container: DependencyContainer) {
super.resolveDependencies(container)
}
}
container.register { Class() }
.resolvingProperties { _, instance in
XCTAssertTrue(instance.resolveDependenciesCalled)
}
container.register { SubClass() }
.resolvingProperties { _, instance in
XCTAssertTrue(instance.resolveDependenciesCalled)
}
let _ = try! container.resolve() as Class
let _ = try! container.resolve() as SubClass
}
func testThatItResolvesCircularDependencies() {
class ResolvableServer: Server, Resolvable {
weak var client: Client?
weak var secondClient: Client?
weak var client: Client!
weak var secondClient: Client!
init(client: Client) {
self.client = client
@@ -452,10 +506,8 @@ class DipTests: XCTestCase {
}
class ResolvableClient: Client, Resolvable {
var server: Server?
var secondServer: Server?
init() {}
var server: Server!
var secondServer: Server!
var didResolveDependenciesCalled = false
@@ -472,14 +524,14 @@ class DipTests: XCTestCase {
}
//given
container.register(.ObjectGraph) { try ResolvableServer(client: self.container.resolve()) as Server }
.resolveDependencies { (container: DependencyContainer, server: Server) in
container.register { try ResolvableServer(client: self.container.resolve()) as Server }
.resolvingProperties { (container: DependencyContainer, server: Server) in
let server = server as! ResolvableServer
server.secondClient = try container.resolve() as Client
}
container.register(.ObjectGraph) { ResolvableClient() as Client }
.resolveDependencies { (container: DependencyContainer, client: Client) in
container.register { ResolvableClient() as Client }
.resolvingProperties { (container: DependencyContainer, client: Client) in
let client = client as! ResolvableClient
client.server = try container.resolve() as Server
client.secondServer = try container.resolve() as Server
@@ -510,24 +562,23 @@ class DipTests: XCTestCase {
var createdService3 = false
var createdService = false
let service = container.register { ServiceImp1() }
.resolveDependencies { container, _ in
container.register { ServiceImp1() }
.resolvingProperties { container, _ in
if container.context.resolvingType == ServiceImp1.self {
createdService1 = true
}
if container.context.resolvingType == Service.self {
createdService = true
}
}
container.register(service, type: Service.self)
}.implements(Service.self)
container.register(tag: "tag") { ServiceImp2() as Service }
.resolveDependencies { _ in
.resolvingProperties { _ in
createdService2 = true
}
container.register() { (arg: String) in ServiceImp1() }
.resolveDependencies { _ in
container.register { (arg: String) in ServiceImp1() }
.resolvingProperties { _ in
createdService3 = true
}
@@ -577,22 +628,24 @@ class DipTests: XCTestCase {
func testThatItFailsValidationOnlyForDipErrors() {
//given
enum SomeError: Error { case error }
container.register { () -> Service in
throw NSError(domain: "", code: 0, userInfo: nil)
throw SomeError.error
}
//then
AssertNoThrow(expression: try container.validate())
//given
let key = DefinitionKey(protocolType: Service.self, argumentsType: Void.self, associatedTag: nil)
let key = DefinitionKey(type: Service.self, typeOfArguments: Void.self, tag: nil)
container.register { () -> Service in
throw DipError.DefinitionNotFound(key: key)
throw DipError.definitionNotFound(key: key)
}
//then
AssertThrows(expression: try container.validate()) { error in
if case let DipError.DefinitionNotFound(_key) = error where _key == key { return true }
if case let DipError.definitionNotFound(_key) = error, _key == key { return true }
else { return false }
}
}
@@ -637,25 +690,24 @@ extension DipTests {
func testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer() {
//given
class ServerImp: Server {
weak var client: Client?
weak var client: Client!
init(client: Client) { self.client = client }
}
class ClientImp: Client {
var server: Server?
var anotherServer: Server?
init() {}
var server: Server!
var anotherServer: Server!
}
let serverContainer = DependencyContainer() { container in
container.register(.ObjectGraph) { ServerImp(client: $0) as Server }
}
let clientContainer = DependencyContainer() { container in
container.register(.ObjectGraph) { ClientImp() as Client }
.resolveDependencies { container, client in
let client = client as! ClientImp
client.server = try container.resolve() as Server
client.anotherServer = try container.resolve() as Server
}
let serverContainer = DependencyContainer()
serverContainer.register { ServerImp(client: $0) as Server }
let clientContainer = DependencyContainer()
clientContainer.register { ClientImp() as Client }
.resolvingProperties { container, client in
let client = client as! ClientImp
client.server = try container.resolve() as Server
client.anotherServer = try container.resolve() as Server
}
//when
@@ -51,8 +51,7 @@ class RuntimeArgumentsTests: XCTestCase {
let container = DependencyContainer()
#if os(Linux)
static var allTests: [(String, RuntimeArgumentsTests -> () throws -> Void)] {
static var allTests = {
return [
("testThatItResolvesInstanceWithOneArgument", testThatItResolvesInstanceWithOneArgument),
("testThatItResolvesInstanceWithTwoArguments", testThatItResolvesInstanceWithTwoArguments),
@@ -66,16 +65,11 @@ class RuntimeArgumentsTests: XCTestCase {
("testThatNewRegistrationWithSameArgumentsOverridesPreviousRegistration", testThatNewRegistrationWithSameArgumentsOverridesPreviousRegistration),
("testThatDifferentFactoriesRegisteredIfArgumentIsOptional", testThatDifferentFactoriesRegisteredIfArgumentIsOptional)
]
}
}()
func setUp() {
container.reset()
}
#else
override func setUp() {
container.reset()
}
#endif
func testThatItResolvesInstanceWithOneArgument() {
//given
@@ -86,13 +80,13 @@ class RuntimeArgumentsTests: XCTestCase {
})
//when
let service = try! container.resolve(withArguments: arg1) as Service
let service = try! container.resolve(arguments: arg1) as Service
//then
XCTAssertTrue(service is ServiceImp1)
//when
let anyService = try! container.resolve(Service.self, withArguments: arg1)
let anyService = try! container.resolve(Service.self, arguments: arg1)
//then
XCTAssertTrue(anyService is ServiceImp1)
@@ -108,13 +102,13 @@ class RuntimeArgumentsTests: XCTestCase {
}
//when
let service = try! container.resolve(withArguments: arg1, arg2) as Service
let service = try! container.resolve(arguments: arg1, arg2) as Service
//then
XCTAssertTrue(service is ServiceImp1)
//when
let anyService = try! container.resolve(Service.self, withArguments: arg1, arg2)
let anyService = try! container.resolve(Service.self, arguments: arg1, arg2)
//then
XCTAssertTrue(anyService is ServiceImp1)
@@ -130,13 +124,13 @@ class RuntimeArgumentsTests: XCTestCase {
}
//when
let service = try! container.resolve(withArguments: arg1, arg2, arg3) as Service
let service = try! container.resolve(arguments: arg1, arg2, arg3) as Service
//then
XCTAssertTrue(service is ServiceImp1)
//when
let anyService = try! container.resolve(Service.self, withArguments: arg1, arg2, arg3)
let anyService = try! container.resolve(Service.self, arguments: arg1, arg2, arg3)
//then
XCTAssertTrue(anyService is ServiceImp1)
@@ -153,13 +147,13 @@ class RuntimeArgumentsTests: XCTestCase {
}
//when
let service = try! container.resolve(withArguments: arg1, arg2, arg3, arg4) as Service
let service = try! container.resolve(arguments: arg1, arg2, arg3, arg4) as Service
//then
XCTAssertTrue(service is ServiceImp1)
//when
let anyService = try! container.resolve(Service.self, withArguments: arg1, arg2, arg3, arg4)
let anyService = try! container.resolve(Service.self, arguments: arg1, arg2, arg3, arg4)
//then
XCTAssertTrue(anyService is ServiceImp1)
@@ -177,13 +171,13 @@ class RuntimeArgumentsTests: XCTestCase {
}
//when
let service = try! container.resolve(withArguments: arg1, arg2, arg3, arg4, arg5) as Service
let service = try! container.resolve(arguments: arg1, arg2, arg3, arg4, arg5) as Service
//then
XCTAssertTrue(service is ServiceImp1)
//when
let anyService = try! container.resolve(Service.self, withArguments: arg1, arg2, arg3, arg4, arg5)
let anyService = try! container.resolve(Service.self, arguments: arg1, arg2, arg3, arg4, arg5)
//then
XCTAssertTrue(anyService is ServiceImp1)
@@ -202,13 +196,13 @@ class RuntimeArgumentsTests: XCTestCase {
}
//when
let service = try! container.resolve(withArguments: arg1, arg2, arg3, arg4, arg5, arg6) as Service
let service = try! container.resolve(arguments: arg1, arg2, arg3, arg4, arg5, arg6) as Service
//then
XCTAssertTrue(service is ServiceImp1)
//when
let anyService = try! container.resolve(Service.self, withArguments: arg1, arg2, arg3, arg4, arg5, arg6)
let anyService = try! container.resolve(Service.self, arguments: arg1, arg2, arg3, arg4, arg5, arg6)
//then
XCTAssertTrue(anyService is ServiceImp1)
@@ -221,8 +215,8 @@ class RuntimeArgumentsTests: XCTestCase {
container.register { (a1: Int, a2: Int) in ServiceImp2() as Service }
//when
let service1 = try! container.resolve(withArguments: arg1) as Service
let service2 = try! container.resolve(withArguments: arg1, arg2) as Service
let service1 = try! container.resolve(arguments: arg1) as Service
let service2 = try! container.resolve(arguments: arg1, arg2) as Service
//then
XCTAssertTrue(service1 is ServiceImp1)
@@ -236,8 +230,8 @@ class RuntimeArgumentsTests: XCTestCase {
container.register(factory: { (a1: String) in ServiceImp2() as Service })
//when
let service1 = try! container.resolve(withArguments: arg1) as Service
let service2 = try! container.resolve(withArguments: arg2) as Service
let service1 = try! container.resolve(arguments: arg1) as Service
let service2 = try! container.resolve(arguments: arg2) as Service
//then
XCTAssertTrue(service1 is ServiceImp1)
@@ -251,8 +245,8 @@ class RuntimeArgumentsTests: XCTestCase {
container.register { (a1: String, a2: Int) in ServiceImp2() as Service }
//when
let service1 = try! container.resolve(withArguments: arg1, arg2) as Service
let service2 = try! container.resolve(withArguments: arg2, arg1) as Service
let service1 = try! container.resolve(arguments: arg1, arg2) as Service
let service2 = try! container.resolve(arguments: arg2, arg1) as Service
//then
XCTAssertTrue(service1 is ServiceImp1)
@@ -263,11 +257,11 @@ class RuntimeArgumentsTests: XCTestCase {
//given
let arg1 = 1, arg2 = 2
container.register { (a1: Int, a2: Int) in ServiceImp1() as Service }
let service1 = try! container.resolve(withArguments: arg1, arg2) as Service
let service1 = try! container.resolve(arguments: arg1, arg2) as Service
//when
container.register { (a1: Int, a2: Int) in ServiceImp2() as Service }
let service2 = try! container.resolve(withArguments: arg1, arg2) as Service
let service2 = try! container.resolve(arguments: arg1, arg2) as Service
//then
XCTAssertTrue(service1 is ServiceImp1)
@@ -276,20 +270,28 @@ class RuntimeArgumentsTests: XCTestCase {
func testThatDifferentFactoriesRegisteredIfArgumentIsOptional() {
//given
let name1 = "1", name2 = "2", name3 = "3"
let name1 = "1", name2 = "2"
container.register { (port: Int, url: String) in ServiceImp(name: name1, baseURL: url, port: port) as Service }
container.register { (port: Int, url: String?) in ServiceImp(name: name2, baseURL: url!, port: port) as Service }
container.register { (port: Int, url: String!) in ServiceImp(name: name3, baseURL: url, port: port) as Service }
//when
let service1 = try! container.resolve(withArguments: 80, "http://example.com") as Service
let service2 = try! container.resolve(withArguments: 80, "http://example.com" as String?) as Service
let service3 = try! container.resolve(withArguments: 80, "http://example.com" as String!) as Service
let service1 = try! container.resolve(arguments: 80, "http://example.com") as Service
let service2 = try! container.resolve(arguments: 80, "http://example.com" as String?) as Service
//then
XCTAssertEqual(service1.name, name1)
XCTAssertEqual(service2.name, name2)
XCTAssertEqual(service3.name, name3)
//Due to incomplete implementation of SE-0054 (bug: https://bugs.swift.org/browse/SR-2143)
//registering definition with T? and T! arguments types will produce two different definitions
//but when argement of T! will be passed to `resolve` method it will be transformed to T?
//and wrong definition will be used
//When fixed using T? and T! should not register two different definitions
// let name3 = "3"
// container.register { (port: Int, url: String!) in ServiceImp(name: name3, baseURL: url, port: port) as Service }
// let service3 = try! container.resolve(arguments: 80, "http://example.com" as String!) as Service
// XCTAssertEqual(service3.name, name3)
}
}
@@ -26,7 +26,7 @@ import XCTest
@testable import Dip
private protocol Server: class {
var client: Client? { get set }
var client: Client! { get set }
}
private protocol Client: class {
@@ -45,11 +45,11 @@ private func ==<T: ClientImp>(lhs: T, rhs: T) -> Bool {
}
private class ServerImp: Server, Hashable {
weak var client: Client?
weak var client: Client!
init() {}
var hashValue: Int {
return unsafeAddressOf(self).hashValue
return Unmanaged.passUnretained(self).toOpaque().hashValue
}
}
@@ -64,24 +64,26 @@ private var container: DependencyContainer!
#if os(Linux)
import Glibc
private var runningThreads: Int = 0
private var lock: pthread_spinlock_t = 0
private let resolveClientSync: () -> Client? = {
var clientPointer: UnsafeMutablePointer<Void> = nil
clientPointer = dispatch_sync { _ in
let pointer = dispatch_sync { _ in
let resolved = try! container.resolve() as Client
return UnsafeMutablePointer(Unmanaged.passUnretained(resolved as! ClientImp).toOpaque())
return UnsafeMutableRawPointer(Unmanaged.passRetained(resolved as! ClientImp).toOpaque())
}
return Unmanaged<ClientImp>.fromOpaque(COpaquePointer(clientPointer)).takeUnretainedValue()
guard let clientPointer = pointer else { return nil }
return Unmanaged<ClientImp>.fromOpaque(clientPointer).takeRetainedValue()
}
#else
let queue = NSOperationQueue()
let lock = NSRecursiveLock()
let queue = OperationQueue()
let lock = RecursiveLock()
private let resolveClientSync: () -> Client? = {
var client: Client?
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
DispatchQueue.global(qos: .default).sync() {
client = try! container.resolve() as Client
}
return client
@@ -90,9 +92,14 @@ private let resolveClientSync: () -> Client? = {
#endif
let resolveServerAsync = {
let service = try! container.resolve() as Server
let server = try! container.resolve() as Server
lock.lock()
resolvedServers.insert(service as! ServerImp)
resolvedServers.insert(server as! ServerImp)
#if os(Linux)
runningThreads -= 1
#endif
lock.unlock()
}
@@ -100,34 +107,33 @@ let resolveClientAsync = {
let client = try! container.resolve() as Client
lock.lock()
resolvedClients.append(client as! ClientImp)
#if os(Linux)
runningThreads -= 1
#endif
lock.unlock()
}
class ThreadSafetyTests: XCTestCase {
#if os(Linux)
required init(name: String, testClosure: XCTestCase throws -> Void) {
required init(name: String, testClosure: @escaping (XCTestCase) throws -> Void) {
pthread_spin_init(&lock, 0)
super.init(name: name, testClosure: testClosure)
}
#endif
static var allTests: [(String, ThreadSafetyTests -> () throws -> Void)] {
static var allTests = {
return [
("testSingletonThreadSafety", testSingletonThreadSafety),
("testFactoryThreadSafety", testFactoryThreadSafety),
("testCircularReferenceThreadSafety", testCircularReferenceThreadSafety)
]
}
}()
func setUp() {
container = DependencyContainer()
}
func tearDown() {
resolvedServers.removeAll()
resolvedClients.removeAll()
}
#else
override func setUp() {
Dip.logLevel = .Verbose
container = DependencyContainer()
}
@@ -135,24 +141,27 @@ class ThreadSafetyTests: XCTestCase {
resolvedServers.removeAll()
resolvedClients.removeAll()
}
#endif
func testSingletonThreadSafety() {
container.register(.Singleton) { ServerImp() as Server }
container.register(.singleton) { ServerImp() as Server }
for _ in 0..<100 {
#if os(Linux)
dispatch_async({ _ in
lock.lock()
runningThreads += 1
lock.unlock()
dispatch_async { _ in
resolveServerAsync()
return nil
})
}
#else
queue.addOperationWithBlock(resolveServerAsync)
queue.addOperation(resolveServerAsync)
#endif
}
#if os(Linux)
sleep(1)
while runningThreads > 0 { sleep(1) }
#else
queue.waitUntilAllOperationsAreFinished()
#endif
@@ -166,17 +175,21 @@ class ThreadSafetyTests: XCTestCase {
for _ in 0..<100 {
#if os(Linux)
dispatch_async({ _ in
lock.lock()
runningThreads += 1
lock.unlock()
dispatch_async { _ in
resolveServerAsync()
return nil
})
}
#else
queue.addOperationWithBlock(resolveServerAsync)
queue.addOperation(resolveServerAsync)
#endif
}
#if os(Linux)
sleep(1)
while runningThreads > 0 { sleep(1) }
#else
queue.waitUntilAllOperationsAreFinished()
#endif
@@ -186,28 +199,32 @@ class ThreadSafetyTests: XCTestCase {
func testCircularReferenceThreadSafety() {
container.register(.ObjectGraph) {
container.register {
ClientImp(server: try container.resolve()) as Client
}
container.register(.ObjectGraph) { ServerImp() as Server }
.resolveDependencies { container, server in
container.register { ServerImp() as Server }
.resolvingProperties { container, server in
server.client = resolveClientSync()
}
for _ in 0..<100 {
#if os(Linux)
dispatch_async({ _ in
lock.lock()
runningThreads += 1
lock.unlock()
dispatch_async { _ in
resolveClientAsync()
return nil
})
}
#else
queue.addOperationWithBlock(resolveClientAsync)
queue.addOperation(resolveClientAsync)
#endif
}
#if os(Linux)
sleep(1)
while runningThreads > 0 { sleep(1) }
#else
queue.waitUntilAllOperationsAreFinished()
#endif
@@ -34,34 +34,32 @@ class TypeForwardingTests: XCTestCase {
let container = DependencyContainer()
#if os(Linux)
static var allTests: [(String, TypeForwardingTests -> () throws -> Void)] {
static var allTests = {
return [
("testThatItResolvesInstanceByTypeForwarding", testThatItResolvesInstanceByTypeForwarding),
("testThatItReusesInstanceResolvedByTypeForwarding", testThatItReusesInstanceResolvedByTypeForwarding),
("testThatItDoesNotResolveByTypeForwardingIfRegisteredForAnotherTag", testThatItDoesNotResolveByTypeForwardingIfRegisteredForAnotherTag),
("testThatItDoesNotReuseInstanceResolvedByTypeForwardingRegisteredForAnotherTag", testThatItDoesNotReuseInstanceResolvedByTypeForwardingRegisteredForAnotherTag),
("testThatItCallsResolvedDependenciesBlockWhenResolvingByTypeForwarding", testThatItCallsResolvedDependenciesBlockWhenResolvingByTypeForwarding),
("testThatItCallsResolvedDependenciesBlockProvidedAfterRegistrationWhenResolvingByTypeForwarding",testThatItCallsResolvedDependenciesBlockProvidedAfterRegistrationWhenResolvingByTypeForwarding),
("testThatItFallbackToDefinitionWithNoTagWhenResolvingInstanceByTypeForwarding", testThatItFallbackToDefinitionWithNoTagWhenResolvingInstanceByTypeForwarding),
("testThatItCanResolveOptional", testThatItCanResolveOptional),
("testThatItFirstUsesTaggedDefinitionWhenResolvingOptional", testThatItFirstUsesTaggedDefinitionWhenResolvingOptional),
("testThatItThrowsErrorWhenResolvingNotImplementedTypeWithTypeForwarding", testThatItThrowsErrorWhenResolvingNotImplementedTypeWithTypeForwarding),
("testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType", testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType)
("testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType", testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType),
("testThatItDoesNotOverrideIfDefinitionForwardsTheSameTypeWithDifferentTag", testThatItDoesNotOverrideIfDefinitionForwardsTheSameTypeWithDifferentTag)
]
}
}()
func setUp() {
container.reset()
}
#else
override func setUp() {
container.reset()
}
#endif
func testThatItResolvesInstanceByTypeForwarding() {
//given
let def = container.register { ServiceImp1() as Service }
container.register(def, type: ForwardedType.self)
container.register(def, type: NSObject.self)
container.register { ServiceImp1() as Service }
.implements(ForwardedType.self)
.implements(NSObject.self)
//when
let anotherService = try! container.resolve() as ForwardedType
@@ -78,9 +76,10 @@ class TypeForwardingTests: XCTestCase {
func testThatItReusesInstanceResolvedByTypeForwarding() {
//given
let def = container.register(.ObjectGraph) { ServiceImp1() as Service }
.resolveDependencies { container, resolved in
container.register() { ServiceImp1() as Service }
.resolvingProperties { container, resolved in
//when
//resolving forwarded type
let forwardType = try container.resolve() as ForwardedType
let anyForwardType = try container.resolve(ForwardedType.self) as! ForwardedType
let object = try container.resolve() as NSObject
@@ -95,26 +94,26 @@ class TypeForwardingTests: XCTestCase {
XCTAssertTrue(anyObject === resolved as! NSObject)
XCTAssertTrue(service === resolved)
XCTAssertTrue(anyService === resolved)
}
container.register(def, type: ForwardedType.self)
container.register(def, type: NSObject.self)
}
.implements(ForwardedType.self)
.implements(NSObject.self)
let _ = try! container.resolve() as Service
let _ = try! container.resolve() as ForwardedType
let _ = try! container.resolve() as NSObject
// let _ = try! container.resolve() as NSObject
}
func testThatItDoesNotResolveByTypeForwardingIfRegisteredForAnotherTag() {
//given
let def = container.register(tag: "tag") { ServiceImp1() as Service }
container.register(def, type: ForwardedType.self, tag: "otherTag")
def.implements(ForwardedType.self, tag: "otherTag")
//then
AssertThrows(expression: try container.resolve(tag: "tag") as ForwardedType)
AssertThrows(expression: try container.resolve(ForwardedType.self, tag: "tag"))
//and given
container.register(def, type: ForwardedType.self, tag: "tag")
def.implements(ForwardedType.self, tag: "tag")
//then
AssertNoThrow(expression: try container.resolve(tag: "tag") as ForwardedType)
@@ -124,11 +123,13 @@ class TypeForwardingTests: XCTestCase {
func testThatItDoesNotReuseInstanceResolvedByTypeForwardingRegisteredForAnotherTag() {
var resolveDependenciesCalled = false
//given
let def = container.register(.ObjectGraph) { ServiceImp1() as Service }
.resolveDependencies { container, service in
container.register() { ServiceImp1() as Service }
.resolvingProperties { container, service in
guard resolveDependenciesCalled == false else { return }
resolveDependenciesCalled = true
//when
//resolving via type-forawrding for tag different then tag for original definition
let forwardType = try container.resolve(tag: "tag") as ForwardedType
let anyForwardType = try container.resolve(ForwardedType.self, tag: "tag") as! ForwardedType
@@ -140,9 +141,9 @@ class TypeForwardingTests: XCTestCase {
XCTAssertFalse(anyForwardType === service as! ForwardedType)
XCTAssertTrue(object === service as! NSObject)
XCTAssertTrue(anyObject === service as! NSObject)
}
container.register(def, type: ForwardedType.self, tag: "tag")
container.register(def, type: NSObject.self)
}
.implements(ForwardedType.self, tag: "tag")
.implements(NSObject.self)
//when
let _ = try! container.resolve() as Service
@@ -150,53 +151,112 @@ class TypeForwardingTests: XCTestCase {
func testThatItCallsResolvedDependenciesBlockWhenResolvingByTypeForwarding() {
//given
var originalResolveDependenciesCalled = false
var resolveDependenciesCalled = false
let def = container.register { ServiceImp1() }
.resolveDependencies { container, service in
originalResolveDependenciesCalled = true
var originalResolvingPropertiesCalled = false
var resolvingPropertiesCalled = false
container.register { ServiceImp1() }
.resolvingProperties { _ in
originalResolvingPropertiesCalled = true
}.implements(Service.self) { _ in
resolvingPropertiesCalled = true
}
//when
let _ = try! container.resolve() as Service
//then
XCTAssertTrue(resolvingPropertiesCalled)
XCTAssertTrue(originalResolvingPropertiesCalled)
//and when
resolvingPropertiesCalled = false
originalResolvingPropertiesCalled = false
let _ = try! container.resolve(Service.self)
//then
XCTAssertTrue(resolvingPropertiesCalled)
XCTAssertTrue(originalResolvingPropertiesCalled)
}
func testThatItCallsResolvedDependenciesBlockProvidedAfterRegistrationWhenResolvingByTypeForwarding() {
//given
//resolvingProperties provided after registering definition
var originalResolvingPropertiesCalled = false
var resolvingPropertiesCalled = false
container.reset()
let definition = container.register { ServiceImp1() }
.implements(Service.self) { container, object in
resolvingPropertiesCalled = true
}
container.register(def, type: Service.self)
.resolveDependencies { container, object in
resolveDependenciesCalled = true
definition.resolvingProperties { _ in
originalResolvingPropertiesCalled = true
}
//when
let _ = try! container.resolve() as Service
//then
XCTAssertTrue(resolveDependenciesCalled)
XCTAssertTrue(originalResolveDependenciesCalled)
XCTAssertTrue(resolvingPropertiesCalled)
XCTAssertTrue(originalResolvingPropertiesCalled)
//and when
resolveDependenciesCalled = false
originalResolveDependenciesCalled = false
resolvingPropertiesCalled = false
originalResolvingPropertiesCalled = false
let _ = try! container.resolve(Service.self)
//then
XCTAssertTrue(resolveDependenciesCalled)
XCTAssertTrue(originalResolveDependenciesCalled)
XCTAssertTrue(resolvingPropertiesCalled)
XCTAssertTrue(originalResolvingPropertiesCalled)
}
func testThatItFallbackToDefinitionWithNoTagWhenResolvingInstanceByTypeForwarding() {
let def = container.register { ServiceImp1() as Service }
container.register { ServiceImp2() as Service }
container.register(def, type: NSObject.self)
//given
container.register { ServiceImp1() as Service }
.implements(ForwardedType.self)
//when
let service = try! container.resolve(tag: "tag") as NSObject
let anyService = try! container.resolve(NSObject.self, tag: "tag")
let service = try! container.resolve(tag: "tag") as ForwardedType
let anyService = try! container.resolve(ForwardedType.self, tag: "tag")
//then
XCTAssertTrue(service is ServiceImp1)
XCTAssertTrue(anyService is ServiceImp1)
}
func testThatItCanResolveOptional() {
container.register { ServiceImp1() as Service }
.implements(ForwardedType.self)
.implements(NSObject.self)
//when
let service = try! container.resolve() as Service?
let anyService = try! container.resolve((Service?).self)
//then
XCTAssertTrue(service is ServiceImp1)
XCTAssertTrue(anyService is ServiceImp1)
//when
let forwardedType = try! container.resolve() as ForwardedType?
let anyForwardedType = try! container.resolve((ForwardedType?).self)
//then
XCTAssertTrue(forwardedType is ServiceImp1)
XCTAssertTrue(anyForwardedType is ServiceImp1)
//when
let object = try! container.resolve() as NSObject?
let anyObject = try! container.resolve((NSObject?).self)
//then
XCTAssertTrue(object is ServiceImp1)
XCTAssertTrue(anyObject is ServiceImp1)
}
func testThatItFirstUsesTaggedDefinitionWhenResolvingOptional() {
let expectedTag: DependencyContainer.Tag = .String("tag")
container.register(tag: expectedTag) { ServiceImp1() as Service }
.resolveDependencies { container, resolved in
.resolvingProperties { container, resolved in
XCTAssertEqual(container.context.tag, expectedTag)
}
container.register { ServiceImp2() as Service }
@@ -212,41 +272,74 @@ class TypeForwardingTests: XCTestCase {
func testThatItThrowsErrorWhenResolvingNotImplementedTypeWithTypeForwarding() {
//given
let def = container.register { ServiceImp1() as Service }
container.register(def, type: NSCoder.self)
container.register { ServiceImp1() as Service }
.implements(ServiceImp2.self)
//then
AssertThrows(expression: try container.resolve() as NSCoder)
AssertThrows(expression: try container.resolve(NSCoder.self))
AssertThrows(expression: try container.resolve() as ServiceImp2) { error in
guard case let DipError.invalidType(_, key) = error else { return false }
let expectedKey = DefinitionKey(type: ServiceImp2.self, typeOfArguments: Void.self, tag: nil)
XCTAssertEqual(key, expectedKey)
return true
}
AssertThrows(expression: try container.resolve(ServiceImp2.self)) { error in
guard case let DipError.invalidType(_, key) = error else { return false }
let expectedKey = DefinitionKey(type: ServiceImp2.self, typeOfArguments: Void.self, tag: nil)
XCTAssertEqual(key, expectedKey)
return true
}
}
func testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType() {
let def1 = container.register { ServiceImp1() as Service }
let def2 = container.register { ServiceImp2() as Service }
container.register(def1, type: NSObject.self)
let def1 = container.register { ServiceImp1() }
let def2 = container.register { ServiceImp2() }
//when
def1.implements(ForwardedType.self)
XCTAssertTrue(try! container.resolve() as NSObject is ServiceImp1)
XCTAssertTrue(try! container.resolve(NSObject.self) is ServiceImp1)
//then
XCTAssertTrue(try! container.resolve() as ForwardedType is ServiceImp1)
XCTAssertTrue(try! container.resolve(ForwardedType.self) is ServiceImp1)
//when
container.register(def2, type: NSObject.self)
//another definition implements the same type
def2.implements(ForwardedType.self)
//then
XCTAssertTrue(try! container.resolve() as NSObject is ServiceImp2)
XCTAssertTrue(try! container.resolve(NSObject.self) is ServiceImp2)
XCTAssertTrue(try! container.resolve() as ForwardedType is ServiceImp2)
XCTAssertTrue(try! container.resolve(ForwardedType.self) is ServiceImp2)
//and given
container.register(def2, type: NSObject.self, tag: "tag")
//when
def1.implements(ForwardedType.self, tag: "tag")
XCTAssertTrue(try! container.resolve(tag: "tag") as NSObject is ServiceImp2)
XCTAssertTrue(try! container.resolve(NSObject.self, tag: "tag") is ServiceImp2)
//then
XCTAssertTrue(try! container.resolve(tag: "tag") as ForwardedType is ServiceImp1)
XCTAssertTrue(try! container.resolve(ForwardedType.self, tag: "tag") is ServiceImp1)
//when
container.register(def1, type: NSObject.self, tag: "tag")
//another definition implements the same type for the same tag
def2.implements(ForwardedType.self, tag: "tag")
//then
XCTAssertTrue(try! container.resolve(tag: "tag") as NSObject is ServiceImp1)
XCTAssertTrue(try! container.resolve(NSObject.self, tag: "tag") is ServiceImp1)
XCTAssertTrue(try! container.resolve(tag: "tag") as ForwardedType is ServiceImp2)
XCTAssertTrue(try! container.resolve(ForwardedType.self, tag: "tag") is ServiceImp2)
}
func testThatItDoesNotOverrideIfDefinitionForwardsTheSameTypeWithDifferentTag() {
let def1 = container.register { ServiceImp1() }
let def2 = container.register { ServiceImp2() }
//when
def1.implements(ForwardedType.self, tag: "tag")
//another definition implements the same type for a different tag
def2.implements(ForwardedType.self, tag: "anotherTag")
//then
XCTAssertTrue(try! container.resolve(tag: "tag") as ForwardedType is ServiceImp1)
XCTAssertTrue(try! container.resolve(ForwardedType.self, tag: "tag") is ServiceImp1)
}
}
@@ -24,22 +24,25 @@
import XCTest
#if os(Linux)
typealias NSObject = AnyObject
#endif
func AssertThrows<T>(file: StaticString = #file, line: UInt = #line, @autoclosure expression: () throws -> T) {
func AssertThrows<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T) {
AssertThrows(file, line: line, expression: expression, "")
}
func AssertThrows<T>(file: StaticString = #file, line: UInt = #line, @autoclosure expression: () throws -> T, _ message: String) {
func AssertThrows<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T, _ message: String) {
AssertThrows(expression: expression, checkError: { _ in true }, message)
}
func AssertThrows<T>(file: StaticString = #file, line: UInt = #line, @autoclosure expression: () throws -> T, checkError: ErrorType -> Bool) {
func AssertThrows<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T, checkError: (Error) -> Bool) {
AssertThrows(file, line: line, expression: expression, checkError: checkError, "")
}
func AssertThrows<T>(file: StaticString = #file, line: UInt = #line, @autoclosure expression: () throws -> T, checkError: ErrorType -> Bool, _ message: String) {
func AssertThrows<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T, checkError: (Error) -> Bool, _ message: String) {
do {
try expression()
let _ = try expression()
XCTFail(message, file: file, line: line)
}
catch {
@@ -47,13 +50,13 @@ func AssertThrows<T>(file: StaticString = #file, line: UInt = #line, @autoclosur
}
}
func AssertNoThrow<T>(file: StaticString = #file, line: UInt = #line, @autoclosure expression: () throws -> T) {
func AssertNoThrow<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T) {
AssertNoThrow(file, line: line, expression: expression, "")
}
func AssertNoThrow<T>(file: StaticString = #file, line: UInt = #line, @autoclosure expression: () throws -> T, _ message: String) {
func AssertNoThrow<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T, _ message: String) {
do {
try expression()
let _ = try expression()
}
catch {
XCTFail(message, file: file, line: line)
@@ -62,17 +65,21 @@ func AssertNoThrow<T>(file: StaticString = #file, line: UInt = #line, @autoclosu
#if os(Linux)
import Glibc
typealias TMain = @convention(c) (UnsafeMutablePointer<Void>) -> UnsafeMutablePointer<Void>
typealias TMain = @convention(c) (UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer?
func dispatch_async(block: TMain) {
private func startThread(_ block: @escaping TMain) -> pthread_t {
var pid: pthread_t = 0
pthread_create(&pid, nil, block, nil)
return pid
}
func dispatch_sync(block: TMain) -> UnsafeMutablePointer<Void> {
var pid: pthread_t = 0
var result: UnsafeMutablePointer<Void> = nil
pthread_create(&pid, nil, block, nil)
func dispatch_async(block: @escaping TMain) -> pthread_t {
return startThread(block)
}
func dispatch_sync(block: @escaping TMain) -> UnsafeMutableRawPointer? {
var result: UnsafeMutableRawPointer? = UnsafeMutableRawPointer.allocate(bytes: 1, alignedTo: 0)
let pid = startThread(block)
pthread_join(pid, &result)
return result
}
+10 -9
View File
@@ -1,13 +1,14 @@
import XCTest
@testable import DipTestSuite
@testable import DipTests
XCTMain([
testCase(DipTests.allTests),
testCase(DefinitionTests.allTests),
testCase(RuntimeArgumentsTests.allTests),
testCase(ComponentScopeTests.allTests),
testCase(AutoInjectionTests.allTests),
testCase(ThreadSafetyTests.allTests),
testCase(AutoWiringTests.allTests),
testCase(ContextTests.allTests)
testCase(DipTests.allTests),
testCase(DefinitionTests.allTests),
testCase(RuntimeArgumentsTests.allTests),
testCase(ComponentScopeTests.allTests),
testCase(AutoInjectionTests.allTests),
// testCase(ThreadSafetyTests.allTests),
testCase(AutoWiringTests.allTests),
testCase(ContextTests.allTests),
testCase(TypeForwardingTests.allTests)
])