Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 593129c63e | |||
| 9a8d919a13 | |||
| 17a2d64361 | |||
| 27037c2dd7 | |||
| bd253f4b0a | |||
| 882b2a2031 | |||
| 6a14c1f96d | |||
| f60e322445 | |||
| 77f6fde2fa | |||
| a8f7a2972a | |||
| ce9088afc7 | |||
| ef563c65ba | |||
| 90ff39c720 | |||
| e45dbd634f | |||
| d5b07b1916 | |||
| 33993df68a | |||
| dadb68862a | |||
| 2e53aa8ae2 | |||
| 142a348b20 | |||
| 88f101639d | |||
| 5e70633ece | |||
| af57aa26ed | |||
| 6d6d77d603 | |||
| 8d2f6ab8fb | |||
| 2cc5310d4b | |||
| 5cb03a11bb | |||
| aff01c541b | |||
| a8dd47cee5 | |||
| 12738a665f | |||
| 9e7bd51bcd | |||
| ce394e7d2b | |||
| cd2c66f4a8 | |||
| 5464f00bad | |||
| 5b9cc50190 | |||
| a7c8616300 | |||
| 8349fbd8d8 | |||
| 4b1ecbcb8e | |||
| 2f0e1fdb10 | |||
| 4a8a1daeca | |||
| 56554147cb | |||
| a554454afe | |||
| dde2e98953 | |||
| a2c04ed61e | |||
| c64cf720b8 | |||
| 3429c6ae0b | |||
| 451fb03bc8 | |||
| b1ad2a65b2 | |||
| 3f8b83b87c | |||
| b7bf4904e9 | |||
| 199b1aec8f | |||
| 22d19697f1 | |||
| d809177273 | |||
| 420c866726 | |||
| 6e6cc0b1df | |||
| b71f50cef5 | |||
| 462d528474 | |||
| 01c318bd5c | |||
| a0c890c931 | |||
| 9b2a7918d8 | |||
| 218b5a4e9a | |||
| 0b221f3368 | |||
| 3b943c10ef | |||
| a1da60bd14 | |||
| 1825cd7d4c | |||
| e7d8fb41e1 | |||
| 1c398defeb | |||
| ab561546f0 | |||
| c0fb925ab8 | |||
| 80ee4865ce | |||
| d95df1343e | |||
| a83d866cbd | |||
| cc1dcba4b9 | |||
| 0ceb6a3503 | |||
| 4e641a6465 | |||
| 35b6da8556 | |||
| 47bc1913e3 | |||
| 24d341503e | |||
| 3c1331089b | |||
| 7af8957a01 | |||
| 6b68bea55d | |||
| 5b2168ecef | |||
| 5eb0eece56 |
+1
-1
@@ -1 +1 @@
|
||||
3.0
|
||||
4.2
|
||||
|
||||
+7
-28
@@ -5,18 +5,16 @@ matrix:
|
||||
- script:
|
||||
- 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 spec lint
|
||||
- pod spec lint --allow-warnings
|
||||
- carthage build --no-skip-current
|
||||
- swift package clean && swift build && swift test
|
||||
os: osx
|
||||
osx_image: xcode8
|
||||
osx_image: xcode10
|
||||
language: objective-c
|
||||
before_install:
|
||||
- gem install cocoapods --version 1.1.0.rc.2 --no-document
|
||||
- gem install cocoapods --version 1.6.0.beta.1 --no-document
|
||||
- script:
|
||||
- swift build --clean && swift build && swift test
|
||||
- swift package clean && swift build && swift test
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
@@ -24,30 +22,11 @@ matrix:
|
||||
before_install:
|
||||
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
|
||||
- cd ..
|
||||
- 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
|
||||
- export SWIFT_VERSION=swift-4.2-RELEASE
|
||||
- wget https://swift.org/builds/swift-4.2-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}"
|
||||
- cd Dip
|
||||
- script:
|
||||
- swift build --clean && swift build
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
language: generic
|
||||
before_install:
|
||||
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
|
||||
- cd ..
|
||||
- export SWIFT_VERSION=swift-DEVELOPMENT-SNAPSHOT-2016-09-07-a
|
||||
- wget https://swift.org/builds/development/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 Dip
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
@@ -1,5 +1,48 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 7.0.0
|
||||
|
||||
* Swift 4.2 support.
|
||||
* Fixed some issues when reusing instances previously resolved as optionals.
|
||||
* Dip-UI is now part of Dip.
|
||||
|
||||
## 6.1
|
||||
|
||||
* Swift 4.1 support.
|
||||
* Fixed crashes resolving singletons using collaborating containers.
|
||||
[#179](https://github.com/AliSoftware/Dip/pull/179), [@trimmurrti](https://github.com/trimmurrti)
|
||||
[#182](https://github.com/AliSoftware/Dip/pull/182), [@tapsandswipes](https://github.com/tapsandswipes)
|
||||
|
||||
## 6.0
|
||||
|
||||
* Swift 4 support
|
||||
* Fixed unneeded reuse of singletons in collaborating containers.
|
||||
Containers now first attempt to autowire components and fallback to collaboration when it fails.
|
||||
[#169](https://github.com/AliSoftware/Dip/issues/169), [@ilyapuchka](https://github.com/ilyapuchka)
|
||||
|
||||
## 5.1
|
||||
|
||||
* Dropped Swift 2.3 support.
|
||||
[#150](https://github.com/AliSoftware/Dip/issues/150), [@ilyapuchka](https://github.com/ilyapuchka)
|
||||
* Added custom logging function.
|
||||
[#146](https://github.com/AliSoftware/Dip/issues/146), [@Pr0Ger](https://github.com/Pr0Ger)
|
||||
|
||||
#### Fixed
|
||||
|
||||
* Fixed Swift 3.1 warnings.
|
||||
[#145](https://github.com/AliSoftware/Dip/issues/145), [@DenHeadless](https://github.com/DenHeadless)
|
||||
* Fixed collaboration shared references.
|
||||
[#151](https://github.com/AliSoftware/Dip/issues/151), [@ilyapuchka](https://github.com/ilyapuchka)
|
||||
* Fixed autowiring when using tags.
|
||||
[#154](https://github.com/AliSoftware/Dip/issues/154), [@ilyapuchka](https://github.com/ilyapuchka)
|
||||
|
||||
## 5.0.4
|
||||
|
||||
#### Fixed
|
||||
|
||||
* Fixed broken compatibility for Swift 2.3 API in `resolve(tag:arguments:)` method.
|
||||
[#135](https://github.com/AliSoftware/Dip/issues/135), [@ilyapuchka](https://github.com/ilyapuchka)
|
||||
|
||||
## 5.0.3
|
||||
|
||||
* Added Swift 2.3 compatibility. `swift2.3` brunch is no longer maintained.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "Dip"
|
||||
s.version = "5.0.3"
|
||||
s.version = "7.0.0"
|
||||
s.summary = "Dependency Injection for Swift made easy."
|
||||
|
||||
s.description = <<-DESC
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -27,17 +27,12 @@
|
||||
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 */; };
|
||||
09FC48061DAA9AC700566AA8 /* Resolve_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48041DAA9AC700566AA8 /* Resolve_swift2.swift */; };
|
||||
09FC48071DAA9AC700566AA8 /* Resolve.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48051DAA9AC700566AA8 /* Resolve.swift */; };
|
||||
09FC480F1DAA9CAF00566AA8 /* Register.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC480C1DAA9CAF00566AA8 /* Register.swift */; };
|
||||
09FC48101DAA9CAF00566AA8 /* Register_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC480D1DAA9CAF00566AA8 /* Register_swift2.swift */; };
|
||||
09FC48141DAA9E0200566AA8 /* AutoInjection_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48121DAA9E0200566AA8 /* AutoInjection_swift2.swift */; };
|
||||
09FC48181DAAA53100566AA8 /* DipError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48161DAAA53100566AA8 /* DipError.swift */; };
|
||||
09FC48191DAAA53100566AA8 /* DipError_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48171DAAA53100566AA8 /* DipError_swift2.swift */; };
|
||||
09FC481B1DAAA82800566AA8 /* RuntimeArguments_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC481A1DAAA82800566AA8 /* RuntimeArguments_swift2.swift */; };
|
||||
09FC481E1DAAA8F900566AA8 /* ComponentScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC481C1DAAA8F900566AA8 /* ComponentScope.swift */; };
|
||||
09FC481F1DAAA8F900566AA8 /* ComponentScope_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC481D1DAAA8F900566AA8 /* ComponentScope_swift2.swift */; };
|
||||
09FC48211DAAAC4700566AA8 /* TypeForwarding_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48201DAAAC4700566AA8 /* TypeForwarding_swift2.swift */; };
|
||||
63937A6A21524C0B00AEE75A /* StoryboardInstantiatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63937A6921524C0B00AEE75A /* StoryboardInstantiatable.swift */; };
|
||||
63937A6F21524DA300AEE75A /* DipUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63937A6B21524DA200AEE75A /* DipUITests.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -74,17 +69,15 @@
|
||||
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>"; };
|
||||
09FC48041DAA9AC700566AA8 /* Resolve_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Resolve_swift2.swift; path = ../../Sources/Resolve_swift2.swift; sourceTree = "<group>"; };
|
||||
09FC48051DAA9AC700566AA8 /* Resolve.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Resolve.swift; path = ../../Sources/Resolve.swift; sourceTree = "<group>"; };
|
||||
09FC480C1DAA9CAF00566AA8 /* Register.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Register.swift; path = ../../Sources/Register.swift; sourceTree = "<group>"; };
|
||||
09FC480D1DAA9CAF00566AA8 /* Register_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Register_swift2.swift; path = ../../Sources/Register_swift2.swift; sourceTree = "<group>"; };
|
||||
09FC48121DAA9E0200566AA8 /* AutoInjection_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AutoInjection_swift2.swift; path = ../../Sources/AutoInjection_swift2.swift; sourceTree = "<group>"; };
|
||||
09FC48161DAAA53100566AA8 /* DipError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DipError.swift; path = ../../Sources/DipError.swift; sourceTree = "<group>"; };
|
||||
09FC48171DAAA53100566AA8 /* DipError_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DipError_swift2.swift; path = ../../Sources/DipError_swift2.swift; sourceTree = "<group>"; };
|
||||
09FC481A1DAAA82800566AA8 /* RuntimeArguments_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RuntimeArguments_swift2.swift; path = ../../Sources/RuntimeArguments_swift2.swift; sourceTree = "<group>"; };
|
||||
09FC481C1DAAA8F900566AA8 /* ComponentScope.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComponentScope.swift; path = ../../Sources/ComponentScope.swift; sourceTree = "<group>"; };
|
||||
09FC481D1DAAA8F900566AA8 /* ComponentScope_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComponentScope_swift2.swift; path = ../../Sources/ComponentScope_swift2.swift; sourceTree = "<group>"; };
|
||||
09FC48201DAAAC4700566AA8 /* TypeForwarding_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TypeForwarding_swift2.swift; path = ../../Sources/TypeForwarding_swift2.swift; sourceTree = "<group>"; };
|
||||
63937A6921524C0B00AEE75A /* StoryboardInstantiatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StoryboardInstantiatable.swift; path = ../../Sources/StoryboardInstantiatable.swift; sourceTree = "<group>"; };
|
||||
63937A6B21524DA200AEE75A /* DipUITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DipUITests.swift; path = ../../Tests/DipTests/DipUITests.swift; sourceTree = "<group>"; };
|
||||
63937A6C21524DA200AEE75A /* NSStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NSStoryboard.storyboard; sourceTree = "<group>"; };
|
||||
63937A6D21524DA300AEE75A /* TVStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = TVStoryboard.storyboard; sourceTree = "<group>"; };
|
||||
63937A6E21524DA300AEE75A /* UIStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UIStoryboard.storyboard; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -112,23 +105,17 @@
|
||||
0919F4C91C16417000DC3B10 /* Dip.h */,
|
||||
0919F4CA1C16417000DC3B10 /* Dip.swift */,
|
||||
09FC48161DAAA53100566AA8 /* DipError.swift */,
|
||||
09FC48171DAAA53100566AA8 /* DipError_swift2.swift */,
|
||||
09FC480C1DAA9CAF00566AA8 /* Register.swift */,
|
||||
09FC480D1DAA9CAF00566AA8 /* Register_swift2.swift */,
|
||||
09FC48051DAA9AC700566AA8 /* Resolve.swift */,
|
||||
09FC48041DAA9AC700566AA8 /* Resolve_swift2.swift */,
|
||||
0919F4C81C16417000DC3B10 /* Definition.swift */,
|
||||
09FC481C1DAAA8F900566AA8 /* ComponentScope.swift */,
|
||||
09FC481D1DAAA8F900566AA8 /* ComponentScope_swift2.swift */,
|
||||
0919F4CC1C16417000DC3B10 /* RuntimeArguments.swift */,
|
||||
09FC481A1DAAA82800566AA8 /* RuntimeArguments_swift2.swift */,
|
||||
09873F551C1E0237000C02F6 /* AutoInjection.swift */,
|
||||
09FC48121DAA9E0200566AA8 /* AutoInjection_swift2.swift */,
|
||||
09B035FF1C5D2B83001EA5B7 /* AutoWiring.swift */,
|
||||
095F829B1D043B41008CD706 /* TypeForwarding.swift */,
|
||||
09FC48201DAAAC4700566AA8 /* TypeForwarding_swift2.swift */,
|
||||
0982AF0B1C5183A000B62463 /* Utils.swift */,
|
||||
09871B401DAA6BF300B40B91 /* Compatibility.swift */,
|
||||
63937A6921524C0B00AEE75A /* StoryboardInstantiatable.swift */,
|
||||
0919F4CB1C16417000DC3B10 /* Info.plist */,
|
||||
);
|
||||
path = Dip;
|
||||
@@ -146,6 +133,10 @@
|
||||
09BD350A1D84E30D00B33E53 /* RuntimeArgumentsTests.swift */,
|
||||
09BD350B1D84E30D00B33E53 /* ThreadSafetyTests.swift */,
|
||||
09BD350C1D84E30D00B33E53 /* TypeForwardingTests.swift */,
|
||||
63937A6B21524DA200AEE75A /* DipUITests.swift */,
|
||||
63937A6C21524DA200AEE75A /* NSStoryboard.storyboard */,
|
||||
63937A6D21524DA300AEE75A /* TVStoryboard.storyboard */,
|
||||
63937A6E21524DA300AEE75A /* UIStoryboard.storyboard */,
|
||||
09BD350D1D84E30D00B33E53 /* Utils.swift */,
|
||||
0919F4D11C16417000DC3B10 /* Info.plist */,
|
||||
);
|
||||
@@ -210,6 +201,7 @@
|
||||
buildPhases = (
|
||||
0903B35D1C161543002241C1 /* Sources */,
|
||||
0903B35E1C161543002241C1 /* Frameworks */,
|
||||
63937A7721524E3B00AEE75A /* ShellScript */,
|
||||
0903B35F1C161543002241C1 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
@@ -229,7 +221,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0730;
|
||||
LastUpgradeCheck = 0800;
|
||||
LastUpgradeCheck = 0930;
|
||||
ORGANIZATIONNAME = AliSoftware;
|
||||
TargetAttributes = {
|
||||
0903B3571C161543002241C1 = {
|
||||
@@ -277,6 +269,26 @@
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
63937A7721524E3B00AEE75A /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "echo \"${SRCROOT}/DipTests/${STORYBOARD_NAME_PREFIX}Storyboard.storyboard\"\nibtool --compilation-directory \"${TARGET_TEMP_DIR}\" \"${SRCROOT}/DipTests/${STORYBOARD_NAME_PREFIX}Storyboard.storyboard\"\nibtool --link \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\" \"${TARGET_TEMP_DIR}/${STORYBOARD_NAME_PREFIX}Storyboard.storyboardc\"\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
0903B3531C161543002241C1 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
@@ -284,23 +296,17 @@
|
||||
files = (
|
||||
09871B411DAA6BF300B40B91 /* Compatibility.swift in Sources */,
|
||||
0982AF0C1C5183A000B62463 /* Utils.swift in Sources */,
|
||||
09FC481F1DAAA8F900566AA8 /* ComponentScope_swift2.swift in Sources */,
|
||||
0919F4D51C16417B00DC3B10 /* Definition.swift in Sources */,
|
||||
09FC48061DAA9AC700566AA8 /* Resolve_swift2.swift in Sources */,
|
||||
09FC48101DAA9CAF00566AA8 /* Register_swift2.swift in Sources */,
|
||||
09FC48191DAAA53100566AA8 /* DipError_swift2.swift in Sources */,
|
||||
09FC481E1DAAA8F900566AA8 /* ComponentScope.swift in Sources */,
|
||||
09FC48211DAAAC4700566AA8 /* TypeForwarding_swift2.swift in Sources */,
|
||||
63937A6A21524C0B00AEE75A /* StoryboardInstantiatable.swift in Sources */,
|
||||
09B036001C5D2B83001EA5B7 /* AutoWiring.swift in Sources */,
|
||||
0919F4D41C16417B00DC3B10 /* Dip.swift in Sources */,
|
||||
09FC481B1DAAA82800566AA8 /* RuntimeArguments_swift2.swift in Sources */,
|
||||
09FC480F1DAA9CAF00566AA8 /* Register.swift in Sources */,
|
||||
09FC48071DAA9AC700566AA8 /* Resolve.swift in Sources */,
|
||||
095F829C1D043B41008CD706 /* TypeForwarding.swift in Sources */,
|
||||
09873F561C1E0237000C02F6 /* AutoInjection.swift in Sources */,
|
||||
09FC48181DAAA53100566AA8 /* DipError.swift in Sources */,
|
||||
0919F4D61C16417B00DC3B10 /* RuntimeArguments.swift in Sources */,
|
||||
09FC48141DAA9E0200566AA8 /* AutoInjection_swift2.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -310,6 +316,7 @@
|
||||
files = (
|
||||
09BD35141D84E30D00B33E53 /* RuntimeArgumentsTests.swift in Sources */,
|
||||
09BD35151D84E30D00B33E53 /* ThreadSafetyTests.swift in Sources */,
|
||||
63937A6F21524DA300AEE75A /* DipUITests.swift in Sources */,
|
||||
09BD35121D84E30D00B33E53 /* DefinitionTests.swift in Sources */,
|
||||
09BD350F1D84E30D00B33E53 /* AutoWiringTests.swift in Sources */,
|
||||
09BD35111D84E30D00B33E53 /* ContextTests.swift in Sources */,
|
||||
@@ -353,6 +360,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.Dip;
|
||||
PRODUCT_NAME = Dip;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -372,6 +380,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.Dip;
|
||||
PRODUCT_NAME = Dip;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -387,7 +396,13 @@
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STORYBOARD_NAME_PREFIX = NS;
|
||||
"STORYBOARD_NAME_PREFIX[sdk=appletvos*]" = TV;
|
||||
"STORYBOARD_NAME_PREFIX[sdk=appletvsimulator*]" = TV;
|
||||
"STORYBOARD_NAME_PREFIX[sdk=iphoneos*]" = UI;
|
||||
"STORYBOARD_NAME_PREFIX[sdk=iphonesimulator*]" = UI;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -403,6 +418,8 @@
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STORYBOARD_NAME_PREFIX = "";
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -414,20 +431,28 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
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_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
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 = 5.0.3;
|
||||
CURRENT_PROJECT_VERSION = 7.0.0;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -452,7 +477,7 @@
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,3,4";
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
@@ -469,20 +494,28 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
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_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
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 = 5.0.3;
|
||||
CURRENT_PROJECT_VERSION = 7.0.0;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -500,7 +533,7 @@
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,3,4";
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "0930"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -40,8 +40,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<string>7.0.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<string>7.0.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14313.18"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Dip View Controller-->
|
||||
<scene sceneID="adI-oe-5KL">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="DipViewController" id="fzZ-tH-vfC" customClass="DipViewController" customModule="DipTests" sceneMemberID="viewController">
|
||||
<view key="view" id="vso-jO-9Ex">
|
||||
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="dipTag" value="vc"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</viewController>
|
||||
<customObject id="wjM-mL-nmG" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="311" y="339"/>
|
||||
</scene>
|
||||
<!--Nil Tag View Controller-->
|
||||
<scene sceneID="OhX-tC-zpS">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="NilTagViewController" id="35S-Ec-qEA" customClass="NilTagViewController" customModule="DipTests" sceneMemberID="viewController">
|
||||
<view key="view" id="y58-K4-cDZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="nil" keyPath="dipTag"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</viewController>
|
||||
<customObject id="pvf-jv-8Cj" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="874" y="339"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="Rwu-gt-fAa">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="ViewController" id="tne-ER-mvb" sceneMemberID="viewController">
|
||||
<view key="view" id="Kwe-OO-w0D">
|
||||
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<customObject id="0u1-hv-ZtW" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="311" y="729"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="14313.18" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="ctX-Lj-Yrr">
|
||||
<device id="appleTV" orientation="landscape">
|
||||
<adaptation id="light"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Dip View Controller-->
|
||||
<scene sceneID="0jz-eb-APg">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="DipViewController" id="ctX-Lj-Yrr" customClass="DipViewController" customModule="DipTests" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="TrC-Rh-efi"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="arQ-XW-qWa"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="syn-UA-YGd">
|
||||
<rect key="frame" x="0.0" y="0.0" width="200" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</view>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<size key="freeformSize" width="200" height="100"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="dipTag" value="vc"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="mq6-CB-g6V" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="563" y="-228"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="gDU-un-krd">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="ViewController" id="UwR-h2-tgS" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="qKG-R0-Nkp"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="vP4-Si-HAL"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="r35-FI-kgS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="200" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</view>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<size key="freeformSize" width="200" height="100"/>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="AIY-qB-Dbe" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="563" y="-16"/>
|
||||
</scene>
|
||||
<!--Nil Tag View Controller-->
|
||||
<scene sceneID="PiH-4i-Txa">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="NilTagViewController" id="ZLb-1s-1ne" customClass="NilTagViewController" customModule="DipTests" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="arU-Ca-km8"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="jw1-4B-Xlt"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="NMo-Oi-l7H">
|
||||
<rect key="frame" x="0.0" y="0.0" width="200" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</view>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<size key="freeformSize" width="200" height="100"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="nil" keyPath="dipTag"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Cid-Yu-0N6" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="821" y="-228"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="5AO-J3-7R4">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="Ole-tM-Q3l">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="ViewController" id="ehZ-7Y-MeO" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="bZ0-tI-Yi9"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="UX3-8G-Z4L"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Jmi-i3-vAY">
|
||||
<rect key="frame" x="0.0" y="0.0" width="200" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<size key="freeformSize" width="200" height="100"/>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="H12-WL-igv" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="646" y="461"/>
|
||||
</scene>
|
||||
<!--Dip View Controller-->
|
||||
<scene sceneID="Lgf-SY-hfd">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="DipViewController" id="5AO-J3-7R4" userLabel="Dip View Controller" customClass="DipViewController" customModule="DipTests" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="JYl-DM-U2W"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="Xg8-gz-BQL"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="aU0-uz-rHf">
|
||||
<rect key="frame" x="0.0" y="0.0" width="200" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<size key="freeformSize" width="200" height="100"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="dipTag" value="vc"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="4iF-mX-EX6" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="646" y="200"/>
|
||||
</scene>
|
||||
<!--Dip View Controller-->
|
||||
<scene sceneID="AUA-qF-7ky">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="NilTagViewController" id="fFP-hb-OdS" userLabel="Dip View Controller" customClass="NilTagViewController" customModule="DipTests" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Sio-ii-jPl"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="bhs-zK-dln"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="4xq-UV-htt">
|
||||
<rect key="frame" x="0.0" y="0.0" width="200" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<size key="freeformSize" width="200" height="100"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="nil" keyPath="dipTag"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="xvW-k9-I9y" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="898" y="200"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,176 +1,2 @@
|
||||
[
|
||||
{
|
||||
"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",
|
||||
}
|
||||
]
|
||||
]
|
||||
@@ -13,7 +13,7 @@ Dip supports three different scopes of objects: _Unique_, _Shared_ and _Singleto
|
||||
* 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 `EagerSingleton` scope is the same as `Singleton` scope but instances with this scope 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 `Unique` scope is the default. To set a scope you pass it as an argument to `register` method.
|
||||
|
||||
@@ -107,7 +107,7 @@ viewController = try MyViewController(apiClient: container.resolve())
|
||||
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.
|
||||
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 antipattern]((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.
|
||||
|
||||
Dependency Injection is a pattern (more precisely - a set of patterns) as well as a singleton. And any pattern can be abused. DI can be used in a [wrong way]((http://www.loosecouplings.com/2011/01/dependency-injection-using-di-container.html)), container can easily become a service locator. You should carefully decide when to use DI, you should not inject everything and everywhere and define a protocol for every single class you use. For every tool there is a right time and the same way as singleton can harm you the same way DI and protocols abuse can make your code unnececerry complex.
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
[](http://cocoapods.org/pods/Dip)
|
||||
[](http://cocoapods.org/pods/Dip)
|
||||
[](https://developer.apple.com/swift)
|
||||
[](https://developer.apple.com/swift)
|
||||
[](https://developer.apple.com/swift)
|
||||
[](https://developer.apple.com/swift)
|
||||
|
||||

|
||||
_Photo courtesy of [www.kevinandamanda.com](http://www.kevinandamanda.com/recipes/appetizer/homemade-soft-cinnamon-sugar-pretzel-bites-with-salted-caramel-dipping-sauce.html)_
|
||||
@@ -19,7 +19,7 @@ It's aimed to be as simple as possible yet provide rich functionality usual for
|
||||
|
||||
* 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** . There is also a **[code generator](https://github.com/ilyapuchka/dipgen)** that can help to simplify registering new components.
|
||||
|
||||
<details>
|
||||
<summary>Basic usage</summary>
|
||||
@@ -148,27 +148,13 @@ File an issue if you have any question. Pull requests are warmly welcome too.
|
||||
|
||||
## Installation
|
||||
|
||||
Since version 5.0.0 Dip is built with Swift 3.0. You can install Dip using your favorite dependency manager:
|
||||
You can install Dip using your favorite dependency manager:
|
||||
|
||||
<details>
|
||||
<summary>CocoaPods</summary>
|
||||
|
||||
`pod "Dip"`
|
||||
|
||||
To build for Swift 2.3 add this code to the bottom of your Podfile
|
||||
|
||||
```ruby
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['SWIFT_VERSION'] = '2.3'
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
> You need at least 1.1.0.rc.2 version of CocoaPods.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
@@ -279,7 +279,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0800;
|
||||
LastUpgradeCheck = 0930;
|
||||
ORGANIZATIONNAME = AliSoftware;
|
||||
TargetAttributes = {
|
||||
0990225E1BC123C000E76F43 = {
|
||||
@@ -427,13 +427,23 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
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_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -461,7 +471,7 @@
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -473,13 +483,23 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
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_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
@@ -498,7 +518,7 @@
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 4.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "0930"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -40,8 +40,8 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
codeCoverageEnabled = "YES"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
@@ -31,6 +41,16 @@
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
@@ -62,6 +82,16 @@
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-152.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<string>7.0.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ struct DummyStarshipProvider : StarshipProviderAPI {
|
||||
var pilotName: String
|
||||
|
||||
func fetchIDs(completion: @escaping ([Int]) -> Void) {
|
||||
let nbShips = pilotName.characters.count
|
||||
let nbShips = pilotName.count
|
||||
completion(Array(0..<nbShips))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
@@ -27,8 +27,8 @@ struct SWAPIPersonProvider : PersonProviderAPI {
|
||||
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)
|
||||
let urlStrings = results.compactMap({ $0["url"] as? String })
|
||||
let ids = urlStrings.compactMap(idFromURLString)
|
||||
|
||||
completion(ids)
|
||||
}
|
||||
@@ -61,7 +61,7 @@ struct SWAPIPersonProvider : PersonProviderAPI {
|
||||
hairColor: hairColor,
|
||||
eyeColor: eyeColor,
|
||||
gender: Gender(rawValue: gender),
|
||||
starshipIDs: starshipURLStrings.flatMap(idFromURLString)
|
||||
starshipIDs: starshipURLStrings.compactMap(idFromURLString)
|
||||
)
|
||||
completion(person)
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,8 @@ struct SWAPIStarshipProvider : StarshipProviderAPI {
|
||||
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)
|
||||
let urlStrings = results.compactMap({ $0["url"] as? String })
|
||||
let ids = urlStrings.compactMap(idFromURLString)
|
||||
|
||||
completion(ids)
|
||||
}
|
||||
@@ -59,7 +59,7 @@ struct SWAPIStarshipProvider : StarshipProviderAPI {
|
||||
manufacturer: manufacturer,
|
||||
crew: crew,
|
||||
passengers: passengers,
|
||||
pilotIDs: pilotIDStrings.flatMap(idFromURLString)
|
||||
pilotIDs: pilotIDStrings.compactMap(idFromURLString)
|
||||
)
|
||||
completion(ship)
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
//
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<string>7.0.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-55
@@ -33,27 +33,21 @@ extension DependencyContainer {
|
||||
//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
|
||||
var superClassMirror = mirror.superclassMirror
|
||||
while superClassMirror != nil {
|
||||
try superClassMirror?.children.forEach(resolveChild)
|
||||
superClassMirror = superClassMirror?._superclassMirror
|
||||
superClassMirror = superClassMirror?.superclassMirror
|
||||
}
|
||||
|
||||
try mirror.children.forEach(resolveChild)
|
||||
}
|
||||
|
||||
private func resolveChild(child: Mirror.Child) throws {
|
||||
#if swift(>=3.0)
|
||||
//HOTFIX for https://bugs.swift.org/browse/SR-2282
|
||||
guard !String(describing: type(of: child.value)).has(prefix: "ImplicitlyUnwrappedOptional") else { return }
|
||||
#endif
|
||||
//HOTFIX for https://bugs.swift.org/browse/SR-2282
|
||||
guard !String(describing: type(of: child.value)).has(prefix: "ImplicitlyUnwrappedOptional") else { return }
|
||||
guard let injectedPropertyBox = child.value as? AutoInjectedPropertyBox else { return }
|
||||
|
||||
#if swift(>=3.0)
|
||||
let wrappedType = type(of: injectedPropertyBox).wrappedType
|
||||
#else
|
||||
let wrappedType = injectedPropertyBox.dynamicType.wrappedType
|
||||
#endif
|
||||
let wrappedType = type(of: injectedPropertyBox).wrappedType
|
||||
let contextKey = DefinitionKey(type: wrappedType, typeOfArguments: Void.self, tag: context.tag)
|
||||
try inContext(key:contextKey, injectedInType: context?.resolvingType, injectedInProperty: child.label, logErrors: false) {
|
||||
try injectedPropertyBox.resolve(self)
|
||||
@@ -88,7 +82,6 @@ public protocol AutoInjectedPropertyBox: class {
|
||||
///The type of wrapped property.
|
||||
static var wrappedType: Any.Type { get }
|
||||
|
||||
#if swift(>=3.0)
|
||||
/**
|
||||
This method will be called by `DependencyContainer` during processing resolved instance properties.
|
||||
In this method you should resolve an instance for wrapped property and store a reference to it.
|
||||
@@ -98,17 +91,6 @@ 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
|
||||
#else
|
||||
/**
|
||||
This method will be called by `DependencyContainer` during processing resolved instance properties.
|
||||
In this method you should resolve an instance for wrapped property and store a reference to it.
|
||||
|
||||
- parameter container: A container to be used to resolve an instance
|
||||
|
||||
- note: This method is not intended to be called manually, `DependencyContainer` will call it by itself.
|
||||
*/
|
||||
func resolve(container: DependencyContainer) throws
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,7 +124,11 @@ public final class Injected<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=3.0)
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new wrapper for auto-injected property.
|
||||
|
||||
@@ -162,11 +148,6 @@ public final class Injected<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox
|
||||
self.init(value: nil, required: required, tag: tag, overrideTag: true, didInject: didInject)
|
||||
}
|
||||
|
||||
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 {
|
||||
let resolved: T? = try super.resolve(with: container)
|
||||
value = resolved
|
||||
@@ -181,13 +162,6 @@ public final class Injected<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox
|
||||
return Injected(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
|
||||
#else
|
||||
init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: (T) -> ()) {
|
||||
self.value = value
|
||||
super.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,11 +216,11 @@ public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropert
|
||||
return valueBox?.value
|
||||
}
|
||||
|
||||
#if swift(>=3.0)
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new wrapper for weak auto-injected property.
|
||||
|
||||
@@ -280,44 +254,28 @@ public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropert
|
||||
return InjectedWeak(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
|
||||
#else
|
||||
init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: (T) -> ()) {
|
||||
self.valueBox = value.map(WeakBox.init)
|
||||
super.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
class _InjectedPropertyBox<T> {
|
||||
public class _InjectedPropertyBox<T> {
|
||||
|
||||
let required: Bool
|
||||
let didInject: (T) -> ()
|
||||
let tag: DependencyContainer.Tag?
|
||||
let overrideTag: Bool
|
||||
|
||||
#if swift(>=3.0)
|
||||
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
|
||||
}
|
||||
#else
|
||||
init(required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: (T) -> () = { _ in }) {
|
||||
self.required = required
|
||||
self.tag = tag?.dependencyTag
|
||||
self.overrideTag = overrideTag
|
||||
self.didInject = didInject
|
||||
}
|
||||
#endif
|
||||
|
||||
func resolve(with container: DependencyContainer) throws -> T? {
|
||||
let tag = overrideTag ? self.tag : container.context.tag
|
||||
do {
|
||||
container.context.key = container.context.key.tagged(with: tag)
|
||||
let key = DefinitionKey(type: T.self, typeOfArguments: Void.self, tag: tag?.dependencyTag)
|
||||
return try resolve(with: container, key: key, builder: { factory in try factory() }) as? T
|
||||
return try resolve(with: container, key: key, builder: { (factory: (Any) throws -> Any) in try factory(()) }) as? T
|
||||
}
|
||||
catch {
|
||||
let error = DipError.autoInjectionFailed(label: container.context.injectedInProperty, type: container.context.resolvingType, underlyingError: error)
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
//
|
||||
// Dip
|
||||
//
|
||||
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if !swift(>=3.0)
|
||||
extension Injected {
|
||||
|
||||
/**
|
||||
Creates a new wrapper for auto-injected property.
|
||||
|
||||
- parameters:
|
||||
- required: Defines if the property is required or not.
|
||||
If container fails to inject required property it will als fail to resolve
|
||||
the instance that defines that property. Default is `true`.
|
||||
- tag: An optional tag to use to lookup definitions when injecting this property. Default is `nil`.
|
||||
- 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 }) {
|
||||
self.init(value: nil, required: required, tag: nil, overrideTag: false, didInject: didInject)
|
||||
}
|
||||
|
||||
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: (T) -> () = { _ in }) {
|
||||
self.init(value: nil, required: required, tag: tag, overrideTag: true, didInject: didInject)
|
||||
}
|
||||
|
||||
|
||||
public func resolve(container: DependencyContainer) throws {
|
||||
let resolved: T? = try super.resolve(with: container)
|
||||
value = resolved
|
||||
}
|
||||
|
||||
/// Returns a new wrapper with provided value.
|
||||
public func setValue(value: T?) -> Injected {
|
||||
guard (required && value != nil) || !required else {
|
||||
fatalError("Can not set required property to nil.")
|
||||
}
|
||||
return Injected(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension InjectedWeak {
|
||||
|
||||
/**
|
||||
Creates a new wrapper for weak auto-injected property.
|
||||
|
||||
- parameters:
|
||||
- required: Defines if the property is required or not.
|
||||
If container fails to inject required property it will als fail to resolve
|
||||
the instance that defines that property. Default is `true`.
|
||||
- tag: An optional tag to use to lookup definitions when injecting this property. Default is `nil`.
|
||||
- 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 }) {
|
||||
self.init(value: nil, required: required, tag: nil, overrideTag: false, didInject: didInject)
|
||||
}
|
||||
|
||||
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: (T) -> () = { _ in }) {
|
||||
self.init(value: nil, required: required, tag: tag, overrideTag: true, didInject: didInject)
|
||||
}
|
||||
|
||||
public func resolve(container: DependencyContainer) throws {
|
||||
let resolved: T? = try super.resolve(with: container)
|
||||
valueBox = resolved.map(WeakBox.init)
|
||||
}
|
||||
|
||||
/// Returns a new wrapper with provided value.
|
||||
public func setValue(value: T?) -> InjectedWeak {
|
||||
guard (required && value != nil) || !required else {
|
||||
fatalError("Can not set required property to nil.")
|
||||
}
|
||||
return InjectedWeak(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -50,19 +50,30 @@ extension DependencyContainer {
|
||||
}
|
||||
|
||||
private func autoWiringDefinition(byKey key: DefinitionKey) throws -> KeyDefinitionPair {
|
||||
do {
|
||||
return try autoWiringDefinition(byKey: key, strictByTag: true)
|
||||
} catch {
|
||||
if key.tag != nil {
|
||||
return try autoWiringDefinition(byKey: key, strictByTag: false)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func autoWiringDefinition(byKey key: DefinitionKey, strictByTag: Bool) throws -> KeyDefinitionPair {
|
||||
var definitions = self.definitions.map({ (key: $0.0, definition: $0.1) })
|
||||
|
||||
definitions = filter(definitions: definitions, byKey: key)
|
||||
definitions = filter(definitions: definitions, byKey: key, strictByTag: strictByTag)
|
||||
definitions = definitions.sorted(by: { $0.definition.numberOfArguments > $1.definition.numberOfArguments })
|
||||
|
||||
|
||||
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: 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 }))
|
||||
|
||||
@@ -1,61 +1,3 @@
|
||||
#if swift(>=3.0)
|
||||
extension Mirror {
|
||||
var _superclassMirror: Mirror? {
|
||||
return superclassMirror
|
||||
}
|
||||
}
|
||||
#else
|
||||
public typealias Error = ErrorType
|
||||
public typealias ExpressibleByIntegerLiteral = IntegerLiteralConvertible
|
||||
public typealias ExpressibleByStringLiteral = StringLiteralConvertible
|
||||
|
||||
extension CollectionType {
|
||||
func sorted(@noescape by isOrderedBefore: (Self.Generator.Element, Self.Generator.Element) -> Bool) -> [Self.Generator.Element] {
|
||||
return sort(isOrderedBefore)
|
||||
}
|
||||
|
||||
func contains(@noescape where predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Bool {
|
||||
return try contains(predicate)
|
||||
}
|
||||
}
|
||||
|
||||
extension CollectionType where Index : RandomAccessIndexType {
|
||||
@warn_unused_result
|
||||
func reversed() -> ReverseRandomAccessCollection<Self> {
|
||||
return reverse()
|
||||
}
|
||||
}
|
||||
|
||||
extension SequenceType where Generator.Element == String {
|
||||
@warn_unused_result
|
||||
func joined(separator aSeparator: String) -> String {
|
||||
return joinWithSeparator(aSeparator)
|
||||
}
|
||||
}
|
||||
|
||||
extension Array {
|
||||
mutating func append<C : CollectionType where C.Generator.Element == Element>(contentsOf newElements: C) {
|
||||
appendContentsOf(newElements)
|
||||
}
|
||||
mutating func append<S : SequenceType where S.Generator.Element == Element>(contentsOf newElements: S) {
|
||||
appendContentsOf(newElements)
|
||||
}
|
||||
}
|
||||
|
||||
extension Mirror {
|
||||
var _superclassMirror: Mirror? {
|
||||
return superclassMirror()
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
init(describing thing: Any) {
|
||||
self.init(thing)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if _runtime(_ObjC)
|
||||
extension String {
|
||||
func has(prefix aPrefix: String) -> Bool {
|
||||
|
||||
@@ -22,103 +22,99 @@
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if swift(>=3.0)
|
||||
|
||||
///Component scope defines a strategy used by the `DependencyContainer` to manage resolved instances life cycle.
|
||||
public enum ComponentScope {
|
||||
|
||||
/**
|
||||
A new instance will be created every time it's resolved.
|
||||
This is a default strategy. Use this strategy when you don't want instances to be shared
|
||||
between different consumers (i.e. if it is not thread safe).
|
||||
|
||||
**Example**:
|
||||
|
||||
```
|
||||
container.register { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
}
|
||||
let consumer = container.resolve() as ServiceConsumer
|
||||
consumer.service1 !== consumer.service2 //true
|
||||
|
||||
```
|
||||
*/
|
||||
case unique
|
||||
|
||||
/**
|
||||
Instance resolved with the same definition will be reused until topmost `resolve(tag:)` method returns.
|
||||
When you resolve the same object graph again the container will create new instances.
|
||||
Use this strategy if you want different object in objects graph to share the same instance.
|
||||
|
||||
- warning: Make sure this component is thread safe or accessed always from the same thread.
|
||||
|
||||
**Example**:
|
||||
|
||||
```
|
||||
container.register { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
}
|
||||
let consumer1 = container.resolve() as ServiceConsumer
|
||||
let consumer2 = container.resolve() as ServiceConsumer
|
||||
consumer1.service1 === consumer1.service2 //true
|
||||
consumer2.service1 === consumer2.service2 //true
|
||||
consumer1.service1 !== consumer2.service1 //true
|
||||
```
|
||||
*/
|
||||
case shared
|
||||
|
||||
/**
|
||||
Resolved instance will be retained by the container and always reused.
|
||||
Do not mix this life cycle with _singleton pattern_.
|
||||
Instance will be not shared between different containers unless they collaborate.
|
||||
|
||||
- warning: Make sure this component is thread safe or accessed always from the same thread.
|
||||
|
||||
- note: When you override or remove definition from the container an instance
|
||||
that was resolved with this definition will be released. When you reset
|
||||
the container it will release all singleton instances.
|
||||
|
||||
**Example**:
|
||||
|
||||
```
|
||||
container.register(.singleton) { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
}
|
||||
let consumer1 = container.resolve() as ServiceConsumer
|
||||
let consumer2 = container.resolve() as ServiceConsumer
|
||||
consumer1.service1 === consumer1.service2 //true
|
||||
consumer2.service1 === consumer2.service2 //true
|
||||
consumer1.service1 === consumer2.service1 //true
|
||||
```
|
||||
*/
|
||||
case singleton
|
||||
|
||||
/**
|
||||
The same scope as a `Singleton`, but instance will be created when container is bootstrapped.
|
||||
|
||||
- seealso: `bootstrap()`
|
||||
*/
|
||||
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
|
||||
|
||||
}
|
||||
///Component scope defines a strategy used by the `DependencyContainer` to manage resolved instances life cycle.
|
||||
public enum ComponentScope {
|
||||
|
||||
#endif
|
||||
/**
|
||||
A new instance will be created every time it's resolved.
|
||||
This is a default strategy. Use this strategy when you don't want instances to be shared
|
||||
between different consumers (i.e. if it is not thread safe).
|
||||
|
||||
**Example**:
|
||||
|
||||
```
|
||||
container.register { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
}
|
||||
let consumer = container.resolve() as ServiceConsumer
|
||||
consumer.service1 !== consumer.service2 //true
|
||||
|
||||
```
|
||||
*/
|
||||
case unique
|
||||
|
||||
/**
|
||||
Instance resolved with the same definition will be reused until topmost `resolve(tag:)` method returns.
|
||||
When you resolve the same object graph again the container will create new instances.
|
||||
Use this strategy if you want different object in objects graph to share the same instance.
|
||||
|
||||
- warning: Make sure this component is thread safe or accessed always from the same thread.
|
||||
|
||||
**Example**:
|
||||
|
||||
```
|
||||
container.register { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
}
|
||||
let consumer1 = container.resolve() as ServiceConsumer
|
||||
let consumer2 = container.resolve() as ServiceConsumer
|
||||
consumer1.service1 === consumer1.service2 //true
|
||||
consumer2.service1 === consumer2.service2 //true
|
||||
consumer1.service1 !== consumer2.service1 //true
|
||||
```
|
||||
*/
|
||||
case shared
|
||||
|
||||
/**
|
||||
Resolved instance will be retained by the container and always reused.
|
||||
Do not mix this life cycle with _singleton pattern_.
|
||||
Instance will be not shared between different containers unless they collaborate.
|
||||
|
||||
- warning: Make sure this component is thread safe or accessed always from the same thread.
|
||||
|
||||
- note: When you override or remove definition from the container an instance
|
||||
that was resolved with this definition will be released. When you reset
|
||||
the container it will release all singleton instances.
|
||||
|
||||
**Example**:
|
||||
|
||||
```
|
||||
container.register(.singleton) { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
}
|
||||
let consumer1 = container.resolve() as ServiceConsumer
|
||||
let consumer2 = container.resolve() as ServiceConsumer
|
||||
consumer1.service1 === consumer1.service2 //true
|
||||
consumer2.service1 === consumer2.service2 //true
|
||||
consumer1.service1 === consumer2.service1 //true
|
||||
```
|
||||
*/
|
||||
case singleton
|
||||
|
||||
/**
|
||||
The same scope as a `Singleton`, but instance will be created when container is bootstrapped.
|
||||
|
||||
- seealso: `bootstrap()`
|
||||
*/
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
//
|
||||
// Dip
|
||||
//
|
||||
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if !swift(>=3.0)
|
||||
|
||||
///Component scope defines a strategy used by the `DependencyContainer` to manage resolved instances life cycle.
|
||||
public enum ComponentScope {
|
||||
|
||||
/**
|
||||
A new instance will be created every time it's resolved.
|
||||
This is a default strategy. Use this strategy when you don't want instances to be shared
|
||||
between different consumers (i.e. if it is not thread safe).
|
||||
|
||||
**Example**:
|
||||
|
||||
```
|
||||
container.register { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
}
|
||||
let consumer = container.resolve() as ServiceConsumer
|
||||
consumer.service1 !== consumer.service2 //true
|
||||
|
||||
```
|
||||
*/
|
||||
case Unique
|
||||
|
||||
/**
|
||||
Instance resolved with the same definition will be reused until topmost `resolve(tag:)` method returns.
|
||||
When you resolve the same object graph again the container will create new instances.
|
||||
Use this strategy if you want different object in objects graph to share the same instance.
|
||||
|
||||
- warning: Make sure this component is thread safe or accessed always from the same thread.
|
||||
|
||||
**Example**:
|
||||
|
||||
```
|
||||
container.register { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
}
|
||||
let consumer1 = container.resolve() as ServiceConsumer
|
||||
let consumer2 = container.resolve() as ServiceConsumer
|
||||
consumer1.service1 === consumer1.service2 //true
|
||||
consumer2.service1 === consumer2.service2 //true
|
||||
consumer1.service1 !== consumer2.service1 //true
|
||||
```
|
||||
*/
|
||||
case Shared
|
||||
|
||||
/**
|
||||
Resolved instance will be retained by the container and always reused.
|
||||
Do not mix this life cycle with _singleton pattern_.
|
||||
Instance will be not shared between different containers unless they collaborate.
|
||||
|
||||
- warning: Make sure this component is thread safe or accessed always from the same thread.
|
||||
|
||||
- note: When you override or remove definition from the container an instance
|
||||
that was resolved with this definition will be released. When you reset
|
||||
the container it will release all singleton instances.
|
||||
|
||||
**Example**:
|
||||
|
||||
```
|
||||
container.register(.singleton) { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
}
|
||||
let consumer1 = container.resolve() as ServiceConsumer
|
||||
let consumer2 = container.resolve() as ServiceConsumer
|
||||
consumer1.service1 === consumer1.service2 //true
|
||||
consumer2.service1 === consumer2.service2 //true
|
||||
consumer1.service1 === consumer2.service1 //true
|
||||
```
|
||||
*/
|
||||
case Singleton
|
||||
|
||||
/**
|
||||
The same scope as a `Singleton`, but instance will be created when container is bootstrapped.
|
||||
|
||||
- seealso: `bootstrap()`
|
||||
*/
|
||||
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
|
||||
|
||||
static var unique: ComponentScope { return .Unique }
|
||||
static var shared: ComponentScope { return .Shared }
|
||||
static var singleton: ComponentScope { return .Singleton }
|
||||
static var weakSingleton: ComponentScope { return .WeakSingleton }
|
||||
static var eagerSingleton: ComponentScope { return .EagerSingleton }
|
||||
}
|
||||
|
||||
#endif
|
||||
+15
-63
@@ -23,7 +23,7 @@
|
||||
//
|
||||
|
||||
///A key used to store definitons in a container.
|
||||
public struct DefinitionKey : Hashable, CustomStringConvertible {
|
||||
public struct DefinitionKey: Hashable, CustomStringConvertible {
|
||||
public let type: Any.Type
|
||||
public let typeOfArguments: Any.Type
|
||||
public private(set) var tag: DependencyContainer.Tag?
|
||||
@@ -35,7 +35,7 @@ public struct DefinitionKey : Hashable, CustomStringConvertible {
|
||||
}
|
||||
|
||||
public var hashValue: Int {
|
||||
return "\(type)-\(typeOfArguments)-\(tag)".hashValue
|
||||
return "\(type)-\(typeOfArguments)-\(tag.desc)".hashValue
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
@@ -47,15 +47,15 @@ public struct DefinitionKey : Hashable, CustomStringConvertible {
|
||||
tagged.tag = tag
|
||||
return tagged
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Check two definition keys on equality by comparing their `type`, `factoryType` and `tag` properties.
|
||||
public func ==(lhs: DefinitionKey, rhs: DefinitionKey) -> Bool {
|
||||
return
|
||||
lhs.type == rhs.type &&
|
||||
/// Check two definition keys on equality by comparing their `type`, `factoryType` and `tag` properties.
|
||||
public static func ==(lhs: DefinitionKey, rhs: DefinitionKey) -> Bool {
|
||||
return
|
||||
lhs.type == rhs.type &&
|
||||
lhs.typeOfArguments == rhs.typeOfArguments &&
|
||||
lhs.tag == rhs.tag
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///Dummy protocol to store definitions for different types in collection
|
||||
@@ -81,19 +81,11 @@ public final class Definition<T, U>: DefinitionType {
|
||||
var weakFactory: ((Any) throws -> Any)!
|
||||
var resolveProperties: ((DependencyContainer, Any) throws -> ())?
|
||||
|
||||
#if swift(>=3.0)
|
||||
init(scope: ComponentScope, factory: @escaping F) {
|
||||
self.factory = factory
|
||||
self.scope = scope
|
||||
}
|
||||
#else
|
||||
init(scope: ComponentScope, factory: F) {
|
||||
self.factory = factory
|
||||
self.scope = scope
|
||||
}
|
||||
#endif
|
||||
|
||||
#if swift(>=3.0)
|
||||
/**
|
||||
Set the block that will be used to resolve dependencies of the instance.
|
||||
This block will be called before `resolve(tag:)` returns.
|
||||
@@ -132,46 +124,6 @@ public final class Definition<T, U>: DefinitionType {
|
||||
}
|
||||
return self
|
||||
}
|
||||
#else
|
||||
/**
|
||||
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 resolve property dependencies of the instance.
|
||||
|
||||
- returns: modified definition
|
||||
|
||||
- note: To resolve circular dependencies at least one of them should use this block
|
||||
to resolve its dependencies. Otherwise the application will enter an infinite loop and crash.
|
||||
|
||||
- note: You can call this method several times on the same definition.
|
||||
Container will call all provided blocks in the same order.
|
||||
|
||||
**Example**
|
||||
|
||||
```swift
|
||||
container.register { ClientImp(service: try container.resolve() as Service) as Client }
|
||||
|
||||
container.register { ServiceImp() as Service }
|
||||
.resolvingProperties { container, service in
|
||||
service.client = try container.resolve() as Client
|
||||
}
|
||||
```
|
||||
|
||||
*/
|
||||
public func resolvingProperties(block: (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
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Calls `resolveDependencies` block if it was set.
|
||||
func resolveProperties(of instance: Any, container: DependencyContainer) throws {
|
||||
@@ -192,7 +144,7 @@ public final class Definition<T, U>: DefinitionType {
|
||||
//MARK: - TypeForwardingDefinition
|
||||
|
||||
/// Types that can be resolved using this definition.
|
||||
private(set) var implementingTypes: [Any.Type] = [(T?).self, (T!).self]
|
||||
private(set) var implementingTypes: [Any.Type] = [(T?).self]
|
||||
|
||||
/// Return `true` if type can be resolved using this definition
|
||||
func doesImplements(type aType: Any.Type) -> Bool {
|
||||
@@ -246,7 +198,7 @@ public final class Definition<T, U>: DefinitionType {
|
||||
|
||||
//MARK: - _Definition
|
||||
|
||||
protocol _Definition: DefinitionType, AutoWiringDefinition, TypeForwardingDefinition {
|
||||
protocol _Definition: AutoWiringDefinition, TypeForwardingDefinition {
|
||||
var type: Any.Type { get }
|
||||
var scope: ComponentScope { get }
|
||||
var weakFactory: ((Any) throws -> Any)! { get }
|
||||
@@ -256,8 +208,8 @@ protocol _Definition: DefinitionType, AutoWiringDefinition, TypeForwardingDefini
|
||||
|
||||
//MARK: - Type Forwarding
|
||||
|
||||
protocol _TypeForwardingDefinition: TypeForwardingDefinition, _Definition {
|
||||
weak var forwardsTo: _TypeForwardingDefinition? { get }
|
||||
protocol _TypeForwardingDefinition: _Definition {
|
||||
var forwardsTo: _TypeForwardingDefinition? { get }
|
||||
var forwardsFrom: [_TypeForwardingDefinition] { get set }
|
||||
func _implements(type aType: Any.Type)
|
||||
func _implements(types aTypes: [Any.Type])
|
||||
@@ -317,12 +269,12 @@ private func ~=(lhs: KeyDefinitionPair, rhs: KeyDefinitionPair) -> Bool {
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// and which tag matches provided key's tag or is nil if strictByTag is false.
|
||||
/// In the end filters defintions by type of runtime arguments.
|
||||
func filter(definitions _definitions: [KeyDefinitionPair], byKey key: DefinitionKey, byTypeOfArguments: Bool = false) -> [KeyDefinitionPair] {
|
||||
func filter(definitions _definitions: [KeyDefinitionPair], byKey key: DefinitionKey, strictByTag: Bool = false, byTypeOfArguments: Bool = false) -> [KeyDefinitionPair] {
|
||||
let definitions = _definitions
|
||||
.filter({ $0.key.type == key.type || $0.definition.doesImplements(type: key.type) })
|
||||
.filter({ $0.key.tag == key.tag || $0.key.tag == nil })
|
||||
.filter({ $0.key.tag == key.tag || (!strictByTag && $0.key.tag == nil) })
|
||||
if byTypeOfArguments {
|
||||
return definitions.filter({ $0.key.typeOfArguments == key.typeOfArguments })
|
||||
}
|
||||
|
||||
+57
-62
@@ -34,7 +34,7 @@ public final class DependencyContainer {
|
||||
|
||||
- seealso: `DependencyTagConvertible`
|
||||
*/
|
||||
public enum Tag: Equatable {
|
||||
public enum Tag {
|
||||
case String(StringLiteralType)
|
||||
case Int(IntegerLiteralType)
|
||||
}
|
||||
@@ -50,7 +50,7 @@ public final class DependencyContainer {
|
||||
private var _weakCollaborators: [WeakBox<DependencyContainer>] = []
|
||||
var _collaborators: [DependencyContainer] {
|
||||
get {
|
||||
return _weakCollaborators.flatMap({ $0.value })
|
||||
return _weakCollaborators.compactMap({ $0.value })
|
||||
}
|
||||
set {
|
||||
_weakCollaborators = newValue.filter({ $0 !== self }).map(WeakBox.init)
|
||||
@@ -99,19 +99,11 @@ public final class DependencyContainer {
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=3.0)
|
||||
func threadSafe<T>(_ closure: () throws -> T) rethrows -> T {
|
||||
lock.lock()
|
||||
defer { lock.unlock() }
|
||||
return try closure()
|
||||
}
|
||||
#else
|
||||
func threadSafe<T>(@noescape closure: () throws -> T) rethrows -> T {
|
||||
lock.lock()
|
||||
defer { lock.unlock() }
|
||||
return try closure()
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -175,12 +167,15 @@ extension DependencyContainer {
|
||||
/// The label of the property where resolved instance will be auto-injected.
|
||||
private(set) public var injectedInProperty: String?
|
||||
|
||||
let inCollaboration: Bool
|
||||
|
||||
var logErrors: Bool = true
|
||||
|
||||
init(key: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String?) {
|
||||
init(key: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String?, inCollaboration: Bool) {
|
||||
self.key = key
|
||||
self.injectedInType = injectedInType
|
||||
self.injectedInProperty = injectedInProperty
|
||||
self.inCollaboration = inCollaboration
|
||||
}
|
||||
|
||||
public var debugDescription: String {
|
||||
@@ -204,7 +199,7 @@ extension DependencyContainer {
|
||||
|
||||
/// Pushes new context created with provided values and calls block. When block returns previous context is restored.
|
||||
/// When popped to initial (root) context will release all references to resolved instances and call `Resolvable` callbacks.
|
||||
func inContext<T>(key aKey: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String? = nil, logErrors: Bool! = nil, block: () throws -> T) rethrows -> T {
|
||||
func inContext<T>(key aKey: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String? = nil, inCollaboration: Bool = false, container: DependencyContainer? = nil, logErrors: Bool! = nil, block: () throws -> T) rethrows -> T {
|
||||
let key = aKey
|
||||
return try threadSafe {
|
||||
let currentContext = self.context
|
||||
@@ -215,6 +210,10 @@ extension DependencyContainer {
|
||||
//clean instances pool if it is owned not by other container
|
||||
if context == nil {
|
||||
resolvedInstances.resolvedInstances.removeAll()
|
||||
for (key, instance) in resolvedInstances.sharedWeakSingletons {
|
||||
if resolvedInstances.sharedWeakSingletons[key] is WeakBoxType { continue }
|
||||
resolvedInstances.sharedWeakSingletons[key] = WeakBox(instance)
|
||||
}
|
||||
for (key, instance) in resolvedInstances.weakSingletons {
|
||||
if resolvedInstances.weakSingletons[key] is WeakBoxType { continue }
|
||||
resolvedInstances.weakSingletons[key] = WeakBox(instance)
|
||||
@@ -230,7 +229,8 @@ extension DependencyContainer {
|
||||
context = Context(
|
||||
key: key,
|
||||
injectedInType: injectedInType,
|
||||
injectedInProperty: injectedInProperty
|
||||
injectedInProperty: injectedInProperty,
|
||||
inCollaboration: inCollaboration
|
||||
)
|
||||
context.logErrors = logErrors ?? currentContext?.logErrors ?? true
|
||||
|
||||
@@ -265,8 +265,19 @@ 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
|
||||
container._collaborators += [self]
|
||||
container.resolvedInstances.sharedSingletonsBox = self.resolvedInstances.sharedSingletonsBox
|
||||
container.resolvedInstances.sharedWeakSingletonsBox = self.resolvedInstances.sharedWeakSingletonsBox
|
||||
updateCollaborationReferences(between: container, and: self)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateCollaborationReferences(between container: DependencyContainer, and collaborator: DependencyContainer) {
|
||||
for container in container._collaborators {
|
||||
guard container.resolvedInstances.sharedSingletonsBox !== collaborator.resolvedInstances.sharedSingletonsBox else { continue }
|
||||
container.resolvedInstances.sharedSingletonsBox = collaborator.resolvedInstances.sharedSingletonsBox
|
||||
container.resolvedInstances.sharedWeakSingletonsBox = collaborator.resolvedInstances.sharedWeakSingletonsBox
|
||||
updateCollaborationReferences(between: container, and: collaborator)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,11 +289,7 @@ extension DependencyContainer {
|
||||
//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 swift(>=3.0)
|
||||
if let context = collaborator.context, context.resolvingType == key.type && context.tag == key.tag { continue }
|
||||
#else
|
||||
if let context = collaborator.context where context.resolvingType == key.type && context.tag == key.tag { continue }
|
||||
#endif
|
||||
|
||||
do {
|
||||
//Pass current container's instances pool to collect instances resolved by collaborator
|
||||
@@ -292,11 +299,23 @@ extension DependencyContainer {
|
||||
let context = collaborator.context
|
||||
collaborator.context = self.context
|
||||
defer {
|
||||
collaborator.resolvedInstances = resolvedInstances
|
||||
collaborator.context = context
|
||||
collaborator.resolvedInstances = resolvedInstances
|
||||
|
||||
for (key, resolvedSingleton) in self.resolvedInstances.singletons {
|
||||
collaborator.resolvedInstances.singletons[key] = resolvedSingleton
|
||||
}
|
||||
for (key, resolvedSingleton) in self.resolvedInstances.weakSingletons {
|
||||
guard collaborator.definition(matching: key) == nil else { continue }
|
||||
collaborator.resolvedInstances.weakSingletons[key] = resolvedSingleton is WeakBoxType ? resolvedSingleton : WeakBox(resolvedSingleton)
|
||||
}
|
||||
for (key, resolved) in self.resolvedInstances.resolvedInstances {
|
||||
guard collaborator.definition(matching: key) == nil else { continue }
|
||||
collaborator.resolvedInstances.resolvedInstances[key] = resolved
|
||||
}
|
||||
}
|
||||
|
||||
let resolved = try collaborator.inContext(key:key, injectedInType: self.context.injectedInType, injectedInProperty: self.context.injectedInProperty, logErrors: false) {
|
||||
let resolved = try collaborator.inContext(key:key, injectedInType: self.context.injectedInType, injectedInProperty: self.context.injectedInProperty, inCollaboration: true, logErrors: false) {
|
||||
try collaborator._resolve(key: key, builder: builder)
|
||||
}
|
||||
|
||||
@@ -313,7 +332,6 @@ extension DependencyContainer {
|
||||
|
||||
extension DependencyContainer {
|
||||
|
||||
#if swift(>=3.0)
|
||||
/**
|
||||
Removes definition registered in the container.
|
||||
|
||||
@@ -324,18 +342,6 @@ extension DependencyContainer {
|
||||
public func remove<T, U>(_ definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
|
||||
_remove(definition: definition, tag: tag)
|
||||
}
|
||||
#else
|
||||
/**
|
||||
Removes definition registered in the container.
|
||||
|
||||
- parameters:
|
||||
- tag: The tag used to register definition.
|
||||
- definition: The definition to remove
|
||||
*/
|
||||
public func remove<T, U>(definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
|
||||
_remove(definition: definition, tag: tag)
|
||||
}
|
||||
#endif
|
||||
|
||||
func _remove<T, U>(definition aDefinition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
|
||||
let key = DefinitionKey(type: T.self, typeOfArguments: U.self, tag: tag?.dependencyTag)
|
||||
@@ -350,6 +356,8 @@ extension DependencyContainer {
|
||||
definitions[key] = nil
|
||||
resolvedInstances.singletons[key] = nil
|
||||
resolvedInstances.weakSingletons[key] = nil
|
||||
resolvedInstances.sharedSingletons[key] = nil
|
||||
resolvedInstances.sharedWeakSingletons[key] = nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,6 +370,8 @@ extension DependencyContainer {
|
||||
definitions.removeAll()
|
||||
resolvedInstances.singletons.removeAll()
|
||||
resolvedInstances.weakSingletons.removeAll()
|
||||
resolvedInstances.sharedSingletons.removeAll()
|
||||
resolvedInstances.sharedWeakSingletons.removeAll()
|
||||
bootstrapped = false
|
||||
}
|
||||
}
|
||||
@@ -372,7 +382,6 @@ extension DependencyContainer {
|
||||
|
||||
extension DependencyContainer {
|
||||
|
||||
#if swift(>=3.0)
|
||||
/**
|
||||
Validates container configuration trying to resolve each registered definition one by one.
|
||||
If definition fails to be resolved without arguments will search provided arguments array
|
||||
@@ -385,20 +394,6 @@ extension DependencyContainer {
|
||||
public func validate(_ arguments: Any...) throws {
|
||||
try _validate(arguments: arguments)
|
||||
}
|
||||
#else
|
||||
/**
|
||||
Validates container configuration trying to resolve each registered definition one by one.
|
||||
If definition fails to be resolved without arguments will search provided arguments array
|
||||
for arguments matched by type and try to resolve this definition using these arguments.
|
||||
If there are no matching arguments will rethrow original error.
|
||||
|
||||
- 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 {
|
||||
try _validate(arguments: arguments)
|
||||
}
|
||||
#endif
|
||||
|
||||
func _validate(arguments _arguments: [Any]) throws {
|
||||
let arguments = _arguments
|
||||
@@ -406,11 +401,7 @@ extension DependencyContainer {
|
||||
do {
|
||||
//try to resolve key using provided arguments
|
||||
for argumentsSet in arguments {
|
||||
#if swift(>=3.0)
|
||||
guard type(of: argumentsSet) == key.typeOfArguments else { continue }
|
||||
#else
|
||||
guard argumentsSet.dynamicType == key.typeOfArguments else { continue }
|
||||
#endif
|
||||
guard type(of: argumentsSet) == key.typeOfArguments else { continue }
|
||||
do {
|
||||
let _ = try inContext(key:key, injectedInType: nil) {
|
||||
try self._resolve(key: key, builder: { definition throws -> Any in
|
||||
@@ -510,13 +501,17 @@ extension DependencyContainer.Tag: ExpressibleByIntegerLiteral {
|
||||
|
||||
}
|
||||
|
||||
public func ==(lhs: DependencyContainer.Tag, rhs: DependencyContainer.Tag) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case let (.String(lhsString), .String(rhsString)):
|
||||
return lhsString == rhsString
|
||||
case let (.Int(lhsInt), .Int(rhsInt)):
|
||||
return lhsInt == rhsInt
|
||||
default:
|
||||
return false
|
||||
extension DependencyContainer.Tag: Equatable {
|
||||
|
||||
public static func ==(lhs: DependencyContainer.Tag, rhs: DependencyContainer.Tag) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case let (.String(lhsString), .String(rhsString)):
|
||||
return lhsString == rhsString
|
||||
case let (.Int(lhsInt), .Int(rhsInt)):
|
||||
return lhsInt == rhsInt
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if swift(>=3.0)
|
||||
/**
|
||||
Errors thrown by `DependencyContainer`'s methods.
|
||||
|
||||
@@ -92,5 +91,4 @@ public enum DipError: Error, CustomStringConvertible {
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
//
|
||||
// Dip
|
||||
//
|
||||
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if !swift(>=3.0)
|
||||
|
||||
/**
|
||||
Errors thrown by `DependencyContainer`'s methods.
|
||||
|
||||
- seealso: `resolve(tag:)`
|
||||
*/
|
||||
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)
|
||||
|
||||
/**
|
||||
Thrown by `resolve(tag:)` if failed to auto-inject required property.
|
||||
|
||||
- parameters:
|
||||
- label: The name of the property
|
||||
- type: The type of the property
|
||||
- underlyingError: The error that caused auto-injection to fail
|
||||
*/
|
||||
case AutoInjectionFailed(label: String?, type: Any.Type, underlyingError: Error)
|
||||
|
||||
/**
|
||||
Thrown by `resolve(tag:)` if failed to auto-wire a type.
|
||||
|
||||
- parameters:
|
||||
- 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: Error)
|
||||
|
||||
/**
|
||||
Thrown when auto-wiring type if several definitions with the same number of runtime arguments
|
||||
are registered for that type.
|
||||
|
||||
- parameters:
|
||||
- type: The type that failed to be resolved by auto-wiring
|
||||
- definitions: Ambiguous definitions
|
||||
*/
|
||||
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.type)."
|
||||
case let .AutoInjectionFailed(label, type, error):
|
||||
return "Failed to auto-inject property \"\(label.desc)\" of type \(type). \(error)"
|
||||
case let .AutoWiringFailed(type, error):
|
||||
return "Failed to auto-wire type \"\(type)\". \(error)"
|
||||
case let .AmbiguousDefinitions(type, definitions):
|
||||
return "Ambiguous definitions for \(type):\n" +
|
||||
definitions.map({ "\($0)" }).joined(separator: ";\n")
|
||||
case let .InvalidType(resolved, key):
|
||||
return "Resolved instance \(resolved ?? "nil") does not implement expected type \(key.type)."
|
||||
}
|
||||
}
|
||||
|
||||
static func definitionNotFound(key aKey: DefinitionKey) -> DipError {
|
||||
return DipError.DefinitionNotFound(key: aKey)
|
||||
}
|
||||
|
||||
static func autoInjectionFailed(label aLabel: String?, type: Any.Type, underlyingError: Error) -> DipError {
|
||||
return DipError.AutoInjectionFailed(label: aLabel, type: type, underlyingError: underlyingError)
|
||||
}
|
||||
|
||||
static func autoWiringFailed(type aType: Any.Type, underlyingError: Error) -> DipError {
|
||||
return DipError.AutoWiringFailed(type: aType, underlyingError: underlyingError)
|
||||
}
|
||||
|
||||
static func ambiguousDefinitions(type aType: Any.Type, definitions: [DefinitionType]) -> DipError {
|
||||
return DipError.AmbiguousDefinitions(type: aType, definitions: definitions)
|
||||
}
|
||||
|
||||
static func invalidType(resolved _resolved: Any?, key: DefinitionKey) -> DipError {
|
||||
return DipError.InvalidType(resolved: _resolved, key: key)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+34
-34
@@ -22,41 +22,39 @@
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if swift(>=3.0)
|
||||
extension DependencyContainer {
|
||||
/**
|
||||
Registers definition for passed 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:
|
||||
- definition: Definition to register
|
||||
- type: Type to register definition for
|
||||
- tag: Optional tag to associate definition with. Default is `nil`.
|
||||
|
||||
- returns: New definition registered for passed type.
|
||||
*/
|
||||
@discardableResult public func register<T, U, F>(_ definition: Definition<T, U>, type: F.Type, tag: DependencyTagConvertible? = nil) -> Definition<F, U> {
|
||||
return _register(definition: definition, type: type, tag: tag)
|
||||
}
|
||||
|
||||
/**
|
||||
Register definiton in the container and associate it with an optional tag.
|
||||
Will override already registered definition for the same type and factory, associated with the same tag.
|
||||
|
||||
- parameters:
|
||||
- tag: The arbitrary tag to associate this definition with. Pass `nil` to associate with any tag. Default value is `nil`.
|
||||
- definition: The definition to register in the container.
|
||||
|
||||
*/
|
||||
public func register<T, U>(_ definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
|
||||
_register(definition: definition, tag: tag)
|
||||
}
|
||||
|
||||
extension DependencyContainer {
|
||||
/**
|
||||
Registers definition for passed 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:
|
||||
- definition: Definition to register
|
||||
- type: Type to register definition for
|
||||
- tag: Optional tag to associate definition with. Default is `nil`.
|
||||
|
||||
- returns: New definition registered for passed type.
|
||||
*/
|
||||
@discardableResult public func register<T, U, F>(_ definition: Definition<T, U>, type: F.Type, tag: DependencyTagConvertible? = nil) -> Definition<F, U> {
|
||||
return _register(definition: definition, type: type, tag: tag)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Register definiton in the container and associate it with an optional tag.
|
||||
Will override already registered definition for the same type and factory, associated with the same tag.
|
||||
|
||||
- parameters:
|
||||
- tag: The arbitrary tag to associate this definition with. Pass `nil` to associate with any tag. Default value is `nil`.
|
||||
- definition: The definition to register in the container.
|
||||
|
||||
*/
|
||||
public func register<T, U>(_ definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
|
||||
_register(definition: definition, tag: tag)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension DependencyContainer {
|
||||
|
||||
@@ -73,6 +71,8 @@ extension DependencyContainer {
|
||||
definitions[key] = definition
|
||||
resolvedInstances.singletons[key] = nil
|
||||
resolvedInstances.weakSingletons[key] = nil
|
||||
resolvedInstances.sharedSingletons[key] = nil
|
||||
resolvedInstances.sharedWeakSingletons[key] = nil
|
||||
|
||||
if .eagerSingleton == definition.scope {
|
||||
bootstrapQueue.append({ _ = try self.resolve(tag: tag) as T })
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
//
|
||||
// Dip
|
||||
//
|
||||
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if !swift(>=3.0)
|
||||
extension DependencyContainer {
|
||||
/**
|
||||
Registers definition for passed 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:
|
||||
- definition: Definition to register
|
||||
- type: Type to register definition for
|
||||
- tag: Optional tag to associate definition with. Default is `nil`.
|
||||
|
||||
- returns: New definition registered for passed type.
|
||||
*/
|
||||
public func register<T, U, F>(definition: Definition<T, U>, type: F.Type, tag: DependencyTagConvertible? = nil) -> Definition<F, U> {
|
||||
return _register(definition: definition, type: type, tag: tag)
|
||||
}
|
||||
|
||||
/**
|
||||
Register definiton in the container and associate it with an optional tag.
|
||||
Will override already registered definition for the same type and factory, associated with the same tag.
|
||||
|
||||
- parameters:
|
||||
- tag: The arbitrary tag to associate this definition with. Pass `nil` to associate with any tag. Default value is `nil`.
|
||||
- definition: The definition to register in the container.
|
||||
|
||||
*/
|
||||
public func register<T, U>(definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
|
||||
_register(definition: definition, tag: tag)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+178
-139
@@ -22,106 +22,132 @@
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if swift(>=3.0)
|
||||
extension DependencyContainer {
|
||||
|
||||
/**
|
||||
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`, `DipError.InvalidType`
|
||||
|
||||
- returns: An instance of type `T`.
|
||||
|
||||
**Example**:
|
||||
```swift
|
||||
let service = try! container.resolve() as Service
|
||||
let service = try! container.resolve(tag: "service") as Service
|
||||
let service: Service = try! container.resolve()
|
||||
```
|
||||
|
||||
- seealso: `register(_:type:tag:factory:)`
|
||||
*/
|
||||
public func resolve<T>(tag: DependencyTagConvertible? = nil) throws -> T {
|
||||
return try resolve(tag: tag) { factory in try factory() }
|
||||
}
|
||||
|
||||
/**
|
||||
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(_:type:tag:factory:)`
|
||||
*/
|
||||
public func resolve(_ type: Any.Type, tag: DependencyTagConvertible? = nil) throws -> Any {
|
||||
return try resolve(type, tag: tag) { factory in try factory() }
|
||||
}
|
||||
|
||||
/**
|
||||
Resolve an instance of type `T` using generic builder closure that accepts generic factory and returns created instance.
|
||||
|
||||
- parameters:
|
||||
- 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`, `DipError.InvalidType`
|
||||
|
||||
- returns: An instance of type `T`.
|
||||
|
||||
- note: You _should not_ call this method directly, instead call any of other
|
||||
`resolve(tag:)` or `resolve(tag:withArguments:)` methods.
|
||||
You _should_ use this method only to resolve dependency with more runtime arguments than
|
||||
_Dip_ supports (currently it's up to six) like in the following example:
|
||||
|
||||
```swift
|
||||
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: DependencyTagConvertible? = nil, builder: ((U) throws -> T) throws -> T) throws -> T {
|
||||
return try _resolve(tag: tag, builder: builder)
|
||||
}
|
||||
|
||||
/**
|
||||
Resolve an instance of provided type using builder closure. Weakly-typed alternative of `resolve(tag:builder:)`
|
||||
|
||||
- seealso: `resolve(tag:builder:)`
|
||||
*/
|
||||
public func resolve<U>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
|
||||
return try _resolve(type: type, tag: tag, builder: builder)
|
||||
}
|
||||
|
||||
extension DependencyContainer {
|
||||
|
||||
/**
|
||||
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`, `DipError.InvalidType`
|
||||
|
||||
- returns: An instance of type `T`.
|
||||
|
||||
**Example**:
|
||||
```swift
|
||||
let service = try! container.resolve() as Service
|
||||
let service = try! container.resolve(tag: "service") as Service
|
||||
let service: Service = try! container.resolve()
|
||||
```
|
||||
|
||||
- seealso: `register(_:type:tag:factory:)`
|
||||
*/
|
||||
public func resolve<T>(tag: DependencyTagConvertible? = nil) throws -> T {
|
||||
return try _resolve(tag: tag) { (factory: () throws -> T) in try factory() }
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
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(_:type:tag:factory:)`
|
||||
*/
|
||||
public func resolve(_ type: Any.Type, tag: DependencyTagConvertible? = nil) throws -> Any {
|
||||
return try resolve(type, tag: tag) { (factory: () throws -> Any) in try factory() }
|
||||
}
|
||||
|
||||
/**
|
||||
Resolve an instance of type `T` using generic builder closure that accepts generic factory and returns created instance.
|
||||
|
||||
- parameters:
|
||||
- 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`, `DipError.InvalidType`
|
||||
|
||||
- returns: An instance of type `T`.
|
||||
|
||||
- note: You _should not_ call this method directly, instead call any of other
|
||||
`resolve(tag:)` or `resolve(tag:withArguments:)` methods.
|
||||
You _should_ use this method only to resolve dependency with more runtime arguments than
|
||||
_Dip_ supports (currently it's up to six) like in the following example:
|
||||
|
||||
```swift
|
||||
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: DependencyTagConvertible? = nil, builder: ((U) throws -> T) throws -> T) throws -> T {
|
||||
return try _resolve(tag: tag, builder: builder)
|
||||
}
|
||||
|
||||
public func resolve<T>(tag: DependencyTagConvertible? = nil, builder: (() throws -> T) throws -> T) throws -> T {
|
||||
return try _resolve(tag: tag, builder: builder)
|
||||
}
|
||||
|
||||
/**
|
||||
Resolve an instance of provided type using builder closure. Weakly-typed alternative of `resolve(tag:builder:)`
|
||||
|
||||
- seealso: `resolve(tag:builder:)`
|
||||
*/
|
||||
public func resolve<U>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
|
||||
return try _resolve(type: type, tag: tag, builder: builder)
|
||||
}
|
||||
|
||||
public func resolve(_ type: Any.Type, tag: DependencyTagConvertible? = nil, builder: (() throws -> Any) throws -> Any) throws -> Any {
|
||||
return try _resolve(type: type, tag: tag, builder: builder)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension DependencyContainer {
|
||||
|
||||
func _resolve<T>(tag aTag: DependencyTagConvertible? = nil, builder: (() throws -> T) throws -> T) throws -> T {
|
||||
return try resolve(T.self, tag: aTag, builder: { factory in
|
||||
try withoutActuallyEscaping(factory, do: { (factory) throws -> T in
|
||||
try builder({ try factory() as! T })
|
||||
})
|
||||
}) as! T
|
||||
}
|
||||
|
||||
func _resolve(type aType: Any.Type, tag: DependencyTagConvertible? = nil, builder: (() throws -> Any) throws -> Any) throws -> Any {
|
||||
let key = DefinitionKey(type: aType, typeOfArguments: Void.self, tag: tag?.dependencyTag)
|
||||
|
||||
return try inContext(key:key, injectedInType: context?.resolvingType) {
|
||||
try self._resolve(key: key, builder: { definition in
|
||||
try builder { try definition.weakFactory(()) }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func _resolve<T, U>(tag aTag: DependencyTagConvertible? = nil, builder: ((U) throws -> T) throws -> T) throws -> T {
|
||||
return try resolve(T.self, tag: aTag, builder: { factory in
|
||||
try builder({ try factory($0) as! T })
|
||||
try withoutActuallyEscaping(factory, do: { (factory) throws -> T in
|
||||
try builder({ try factory($0) as! T })
|
||||
})
|
||||
}) as! T
|
||||
}
|
||||
|
||||
@@ -138,7 +164,15 @@ extension DependencyContainer {
|
||||
/// Lookup definition by the key and use it to resolve instance. Fallback to the key with `nil` tag.
|
||||
func _resolve<T>(key aKey: DefinitionKey, builder: (_Definition) throws -> T) throws -> T {
|
||||
guard let matching = self.definition(matching: aKey) else {
|
||||
return try collaboratingResolve(key: aKey, builder: builder) ?? autowire(key: aKey)
|
||||
do {
|
||||
return try autowire(key: aKey)
|
||||
} catch {
|
||||
if let resolved = collaboratingResolve(key: aKey, builder: builder) {
|
||||
return resolved
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (key, definition) = matching
|
||||
@@ -165,7 +199,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, let unboxed = box.unboxed as? T {
|
||||
if let box = resolvedInstance as? BoxType, let unboxedAny = box.unboxed, let unboxed = unboxedAny as? T {
|
||||
resolvedInstance = unboxed
|
||||
}
|
||||
|
||||
@@ -177,7 +211,7 @@ extension DependencyContainer {
|
||||
return previouslyResolved
|
||||
}
|
||||
|
||||
resolvedInstances[key: key, inScope: definition.scope] = resolvedInstance
|
||||
resolvedInstances[key: key, inScope: definition.scope, context: context] = resolvedInstance
|
||||
|
||||
if let resolvable = resolvedInstance as? Resolvable {
|
||||
resolvedInstances.resolvableInstances.append(resolvable)
|
||||
@@ -193,7 +227,7 @@ extension DependencyContainer {
|
||||
|
||||
private func previouslyResolved<T>(for definition: _Definition, key: DefinitionKey) -> T? {
|
||||
//first check if exact key was already resolved
|
||||
if let previouslyResolved = resolvedInstances[key: key, inScope: definition.scope] as? T {
|
||||
if let previouslyResolved: T = resolvedInstances[key: key, inScope: definition.scope, context: context] {
|
||||
return previouslyResolved
|
||||
}
|
||||
//then check if any related type was already resolved
|
||||
@@ -201,7 +235,7 @@ extension DependencyContainer {
|
||||
DefinitionKey(type: $0, typeOfArguments: key.typeOfArguments, tag: key.tag)
|
||||
})
|
||||
for key in keys {
|
||||
if let previouslyResolved = resolvedInstances[key: key, inScope: definition.scope] as? T {
|
||||
if let previouslyResolved: T = resolvedInstances[key: key, inScope: definition.scope, context: context] {
|
||||
return previouslyResolved
|
||||
}
|
||||
}
|
||||
@@ -209,7 +243,7 @@ extension DependencyContainer {
|
||||
}
|
||||
|
||||
/// Searches for definition that matches provided key
|
||||
private func definition(matching key: DefinitionKey) -> KeyDefinitionPair? {
|
||||
func definition(matching key: DefinitionKey) -> KeyDefinitionPair? {
|
||||
if let definition = (self.definitions[key] ?? self.definitions[key.tagged(with: nil)]) {
|
||||
return (key, definition)
|
||||
}
|
||||
@@ -232,41 +266,49 @@ class ResolvedInstances {
|
||||
var resolvableInstances = [Resolvable]()
|
||||
|
||||
//singletons are stored using reference type wrapper to be able to share them between containers
|
||||
var singletonsBox = Box<[DefinitionKey: Any]>([:])
|
||||
var singletons: [DefinitionKey: Any] {
|
||||
get { return singletonsBox.unboxed }
|
||||
set { singletonsBox.unboxed = newValue }
|
||||
var sharedSingletonsBox = Box<[DefinitionKey: Any]>([:])
|
||||
var sharedSingletons: [DefinitionKey: Any] {
|
||||
get { return sharedSingletonsBox.unboxed }
|
||||
set { sharedSingletonsBox.unboxed = newValue }
|
||||
}
|
||||
var singletons = [DefinitionKey: Any]()
|
||||
|
||||
var weakSingletonsBox = Box<[DefinitionKey: Any]>([:])
|
||||
var weakSingletons: [DefinitionKey: Any] {
|
||||
get { return weakSingletonsBox.unboxed }
|
||||
set { weakSingletonsBox.unboxed = newValue }
|
||||
var sharedWeakSingletonsBox = Box<[DefinitionKey: Any]>([:])
|
||||
var sharedWeakSingletons: [DefinitionKey: Any] {
|
||||
get { return sharedWeakSingletonsBox.unboxed }
|
||||
set { sharedWeakSingletonsBox.unboxed = newValue }
|
||||
}
|
||||
var weakSingletons = [DefinitionKey: Any]()
|
||||
|
||||
subscript(key key: DefinitionKey, inScope scope: ComponentScope) -> Any? {
|
||||
subscript<T>(key key: DefinitionKey, inScope scope: ComponentScope, context context: DependencyContainer.Context) -> T? {
|
||||
get {
|
||||
if scope == .singleton || scope == .eagerSingleton {
|
||||
return singletons[key]
|
||||
let instance: Any?
|
||||
switch scope {
|
||||
case .singleton, .eagerSingleton:
|
||||
instance = context.inCollaboration ? sharedSingletons[key] : singletons[key]
|
||||
case .weakSingleton:
|
||||
let singletons = context.inCollaboration ? sharedWeakSingletons : weakSingletons
|
||||
if let boxed = singletons[key] as? WeakBoxType { instance = boxed.unboxed }
|
||||
else { instance = singletons[key] }
|
||||
case .shared:
|
||||
instance = resolvedInstances[key]
|
||||
case .unique:
|
||||
return nil
|
||||
}
|
||||
if scope == .weakSingleton {
|
||||
if let boxed = weakSingletons[key] as? WeakBoxType { return boxed.unboxed }
|
||||
else { return weakSingletons[key] }
|
||||
}
|
||||
if scope == .shared {
|
||||
return resolvedInstances[key]
|
||||
}
|
||||
return nil
|
||||
return instance.flatMap { $0 as? T }
|
||||
}
|
||||
set {
|
||||
if scope == .singleton || scope == .eagerSingleton {
|
||||
switch scope {
|
||||
case .singleton, .eagerSingleton:
|
||||
sharedSingletons[key] = newValue
|
||||
singletons[key] = newValue
|
||||
}
|
||||
if scope == .weakSingleton {
|
||||
case .weakSingleton:
|
||||
sharedWeakSingletons[key] = newValue
|
||||
weakSingletons[key] = newValue
|
||||
}
|
||||
if scope == .shared {
|
||||
case .shared:
|
||||
resolvedInstances[key] = newValue
|
||||
case .unique:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,19 +317,16 @@ class ResolvedInstances {
|
||||
|
||||
//MARK: - Resolvable
|
||||
|
||||
#if swift(>=3.0)
|
||||
/// Resolvable protocol provides some extension points for resolving dependencies with property injection.
|
||||
public protocol Resolvable {
|
||||
/// 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()
|
||||
}
|
||||
|
||||
/// Resolvable protocol provides some extension points for resolving dependencies with property injection.
|
||||
public protocol Resolvable {
|
||||
/// 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()
|
||||
}
|
||||
|
||||
extension Resolvable {
|
||||
func resolveDependencies(_ container: DependencyContainer) {}
|
||||
func didResolveDependencies() {}
|
||||
}
|
||||
#endif
|
||||
extension Resolvable {
|
||||
func resolveDependencies(_ container: DependencyContainer) {}
|
||||
func didResolveDependencies() {}
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
//
|
||||
// Dip
|
||||
//
|
||||
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if !swift(>=3.0)
|
||||
extension DependencyContainer {
|
||||
|
||||
/**
|
||||
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`, `DipError.InvalidType`
|
||||
|
||||
- returns: An instance of type `T`.
|
||||
|
||||
**Example**:
|
||||
```swift
|
||||
let service = try! container.resolve() as Service
|
||||
let service = try! container.resolve(tag: "service") as Service
|
||||
let service: Service = try! container.resolve()
|
||||
```
|
||||
|
||||
- seealso: `register(_:type:tag:factory:)`
|
||||
*/
|
||||
public func resolve<T>(tag tag: DependencyTagConvertible? = nil) throws -> T {
|
||||
return try resolve(tag: tag) { factory in try factory() }
|
||||
}
|
||||
|
||||
/**
|
||||
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(_:type:tag:factory:)`
|
||||
*/
|
||||
public func resolve(type: Any.Type, tag: DependencyTagConvertible? = nil) throws -> Any {
|
||||
return try resolve(type, tag: tag) { factory in try factory() }
|
||||
}
|
||||
|
||||
/**
|
||||
Resolve an instance of type `T` using generic builder closure that accepts generic factory and returns created instance.
|
||||
|
||||
- parameters:
|
||||
- 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`, `DipError.InvalidType`
|
||||
|
||||
- returns: An instance of type `T`.
|
||||
|
||||
- note: You _should not_ call this method directly, instead call any of other
|
||||
`resolve(tag:)` or `resolve(tag:withArguments:)` methods.
|
||||
You _should_ use this method only to resolve dependency with more runtime arguments than
|
||||
_Dip_ supports (currently it's up to six) like in the following example:
|
||||
|
||||
```swift
|
||||
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) throws -> T {
|
||||
return try _resolve(tag: tag, builder: builder)
|
||||
}
|
||||
|
||||
/**
|
||||
Resolve an instance of provided type using builder closure. Weakly-typed alternative of `resolve(tag:builder:)`
|
||||
|
||||
- seealso: `resolve(tag:builder:)`
|
||||
*/
|
||||
public func resolve<U>(type: Any.Type, tag: DependencyTagConvertible? = nil, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
|
||||
return try _resolve(type: type, tag: tag, builder: builder)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Resolvable protocol provides some extension points for resolving dependencies with property injection.
|
||||
public protocol Resolvable {
|
||||
/// 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()
|
||||
}
|
||||
|
||||
extension Resolvable {
|
||||
func resolveDependencies(container: DependencyContainer) {}
|
||||
func didResolveDependencies() {}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+225
-228
@@ -22,235 +22,232 @@
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if swift(>=3.0)
|
||||
extension DependencyContainer {
|
||||
|
||||
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`.
|
||||
- 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) 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 }
|
||||
|
||||
//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:))
|
||||
```
|
||||
*/
|
||||
@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, tag: tag)
|
||||
return definition
|
||||
}
|
||||
|
||||
/**
|
||||
Register generic factory and auto-wiring factory and associate it with an optional tag.
|
||||
|
||||
- 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 instance created by the factory.
|
||||
- factory: The factory to register.
|
||||
- numberOfArguments: The number of factory arguments. Will be used on auto-wiring to sort definitions.
|
||||
- autoWiringFactory: The factory to be used on auto-wiring to resolve component.
|
||||
|
||||
- returns: A registered definition.
|
||||
|
||||
- note: You _should not_ call this method directly, instead call any of other `register` methods.
|
||||
You _should_ use this method only to register dependency with more runtime arguments
|
||||
than _Dip_ supports (currently it's up to six) like in the following example:
|
||||
|
||||
```swift
|
||||
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), ...)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Though before you do so you should probably review your design and try to reduce number of depnedencies.
|
||||
*/
|
||||
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, tag: tag)
|
||||
return definition
|
||||
}
|
||||
|
||||
// MARK: 1 Runtime Argument
|
||||
|
||||
/**
|
||||
Register factory that accepts one runtime argument of type `A`. You can use up to six runtime arguments.
|
||||
|
||||
- note: You can have several factories with different number or types of arguments registered for same type,
|
||||
optionally associated with some tags. When container resolves that type it matches the type,
|
||||
__number__, __types__ and __order__ of runtime arguments and optional tag that you pass to `resolve(tag:arguments:)` method.
|
||||
|
||||
- parameters:
|
||||
/**
|
||||
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 this component. Default value is `Shared`.
|
||||
- factory: The factory to register.
|
||||
|
||||
- seealso: `register(_:type:tag:factory:)`
|
||||
*/
|
||||
@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.
|
||||
|
||||
- note: When resolving a type container will first try to use definition
|
||||
that exactly matches types of arguments that you pass to resolve method.
|
||||
If it fails or no such definition is found container will try to _auto-wire_ component.
|
||||
For that it will iterate through all the definitions registered for that type
|
||||
which factories accept any number of runtime arguments and are tagged with the same tag,
|
||||
passed to `resolve` method, or with no tag. Container will try to use these definitions
|
||||
to resolve a component one by one until one of them succeeds, starting with tagged definitions
|
||||
in order of decreasing their's factories number of arguments. If none of them succeds it will
|
||||
throw an error. If it finds two definitions with the same number of arguments - it will throw
|
||||
an error.
|
||||
|
||||
- parameters:
|
||||
- tag: The arbitrary tag to lookup registered definition.
|
||||
- arg1: The first argument to pass to the definition's factory.
|
||||
|
||||
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`
|
||||
|
||||
- returns: An instance of type `T`.
|
||||
|
||||
- seealso: `register(_:type:tag:factory:)`, `resolve(tag:builder:)`
|
||||
*/
|
||||
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:arguments:)`
|
||||
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(_: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:arguments:)`
|
||||
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:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
@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:arguments:)`
|
||||
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:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
@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:arguments:)`
|
||||
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:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
@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:arguments:)`
|
||||
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:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
@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:arguments:)`
|
||||
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:arguments:)`
|
||||
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)) }
|
||||
}
|
||||
|
||||
- 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) 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 }
|
||||
|
||||
//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:))
|
||||
```
|
||||
*/
|
||||
@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, tag: tag)
|
||||
return definition
|
||||
}
|
||||
|
||||
#endif
|
||||
/**
|
||||
Register generic factory and auto-wiring factory and associate it with an optional tag.
|
||||
|
||||
- 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 instance created by the factory.
|
||||
- factory: The factory to register.
|
||||
- numberOfArguments: The number of factory arguments. Will be used on auto-wiring to sort definitions.
|
||||
- autoWiringFactory: The factory to be used on auto-wiring to resolve component.
|
||||
|
||||
- returns: A registered definition.
|
||||
|
||||
- note: You _should not_ call this method directly, instead call any of other `register` methods.
|
||||
You _should_ use this method only to register dependency with more runtime arguments
|
||||
than _Dip_ supports (currently it's up to six) like in the following example:
|
||||
|
||||
```swift
|
||||
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), ...)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Though before you do so you should probably review your design and try to reduce number of depnedencies.
|
||||
*/
|
||||
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, tag: tag)
|
||||
return definition
|
||||
}
|
||||
|
||||
// MARK: 1 Runtime Argument
|
||||
|
||||
/**
|
||||
Register factory that accepts one runtime argument of type `A`. You can use up to six runtime arguments.
|
||||
|
||||
- note: You can have several factories with different number or types of arguments registered for same type,
|
||||
optionally associated with some tags. When container resolves that type it matches the type,
|
||||
__number__, __types__ and __order__ of runtime arguments and optional tag that you pass to `resolve(tag:arguments:)` method.
|
||||
|
||||
- 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 `Shared`.
|
||||
- factory: The factory to register.
|
||||
|
||||
- seealso: `register(_:type:tag:factory:)`
|
||||
*/
|
||||
@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.
|
||||
|
||||
- note: When resolving a type container will first try to use definition
|
||||
that exactly matches types of arguments that you pass to resolve method.
|
||||
If it fails or no such definition is found container will try to _auto-wire_ component.
|
||||
For that it will iterate through all the definitions registered for that type
|
||||
which factories accept any number of runtime arguments and are tagged with the same tag,
|
||||
passed to `resolve` method, or with no tag. Container will try to use these definitions
|
||||
to resolve a component one by one until one of them succeeds, starting with tagged definitions
|
||||
in order of decreasing their's factories number of arguments. If none of them succeds it will
|
||||
throw an error. If it finds two definitions with the same number of arguments - it will throw
|
||||
an error.
|
||||
|
||||
- parameters:
|
||||
- tag: The arbitrary tag to lookup registered definition.
|
||||
- arg1: The first argument to pass to the definition's factory.
|
||||
|
||||
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`
|
||||
|
||||
- returns: An instance of type `T`.
|
||||
|
||||
- seealso: `register(_:type:tag:factory:)`, `resolve(tag:builder:)`
|
||||
*/
|
||||
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:arguments:)`
|
||||
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(_: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:arguments:)`
|
||||
public func resolve<T, A, B>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B) throws -> T {
|
||||
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2)) } as! T
|
||||
}
|
||||
|
||||
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
@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:arguments:)`
|
||||
public func resolve<T, A, B, C>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C) throws -> T {
|
||||
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3)) } as! T
|
||||
}
|
||||
|
||||
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
@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:arguments:)`
|
||||
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(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4)) } as! T
|
||||
}
|
||||
|
||||
/// - seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
@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:arguments:)`
|
||||
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(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5)) } as! T
|
||||
}
|
||||
|
||||
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
@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:arguments:)`
|
||||
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(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5, arg6)) } as! T
|
||||
}
|
||||
|
||||
/// - seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
|
||||
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)) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,256 +0,0 @@
|
||||
//
|
||||
// Dip
|
||||
//
|
||||
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if !swift(>=3.0)
|
||||
|
||||
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`.
|
||||
- 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) 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 }
|
||||
|
||||
//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>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: () throws -> T) -> Definition<T, ()> {
|
||||
let definition = DefinitionBuilder<T, ()> {
|
||||
$0.scope = scope
|
||||
$0.factory = factory
|
||||
}.build()
|
||||
register(definition, tag: tag)
|
||||
return definition
|
||||
}
|
||||
|
||||
/**
|
||||
Register generic factory and auto-wiring factory and associate it with an optional tag.
|
||||
|
||||
- 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 instance created by the factory.
|
||||
- factory: The factory to register.
|
||||
- numberOfArguments: The number of factory arguments. Will be used on auto-wiring to sort definitions.
|
||||
- autoWiringFactory: The factory to be used on auto-wiring to resolve component.
|
||||
|
||||
- returns: A registered definition.
|
||||
|
||||
- note: You _should not_ call this method directly, instead call any of other `register` methods.
|
||||
You _should_ use this method only to register dependency with more runtime arguments
|
||||
than _Dip_ supports (currently it's up to six) like in the following example:
|
||||
|
||||
```swift
|
||||
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), ...)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Though before you do so you should probably review your design and try to reduce number of depnedencies.
|
||||
*/
|
||||
public func register<T, U>(scope: ComponentScope, type: T.Type, tag: DependencyTagConvertible?, factory: (U) throws -> T, numberOfArguments: Int, autoWiringFactory: (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, tag: tag)
|
||||
return definition
|
||||
}
|
||||
|
||||
// MARK: 1 Runtime Argument
|
||||
|
||||
/**
|
||||
Register factory that accepts one runtime argument of type `A`. You can use up to six runtime arguments.
|
||||
|
||||
- note: You can have several factories with different number or types of arguments registered for same type,
|
||||
optionally associated with some tags. When container resolves that type it matches the type,
|
||||
__number__, __types__ and __order__ of runtime arguments and optional tag that you pass to `resolve(tag:arguments:)` method.
|
||||
|
||||
- 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 `Shared`.
|
||||
- factory: The factory to register.
|
||||
|
||||
- seealso: `register(_:type:tag:factory:)`
|
||||
*/
|
||||
public func register<T, A>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A) throws -> T) -> Definition<T, A> {
|
||||
return register(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.
|
||||
|
||||
- note: When resolving a type container will first try to use definition
|
||||
that exactly matches types of arguments that you pass to resolve method.
|
||||
If it fails or no such definition is found container will try to _auto-wire_ component.
|
||||
For that it will iterate through all the definitions registered for that type
|
||||
which factories accept any number of runtime arguments and are tagged with the same tag,
|
||||
passed to `resolve` method, or with no tag. Container will try to use these definitions
|
||||
to resolve a component one by one until one of them succeeds, starting with tagged definitions
|
||||
in order of decreasing their's factories number of arguments. If none of them succeds it will
|
||||
throw an error. If it finds two definitions with the same number of arguments - it will throw
|
||||
an error.
|
||||
|
||||
- parameters:
|
||||
- tag: The arbitrary tag to lookup registered definition.
|
||||
- arg1: The first argument to pass to the definition's factory.
|
||||
|
||||
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`
|
||||
|
||||
- returns: An instance of type `T`.
|
||||
|
||||
- seealso: `register(_:tag:factory:)`, `resolve(tag:builder:)`
|
||||
*/
|
||||
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:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
public func register<T, A, B>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A, B) throws -> T) -> Definition<T, (A, B)> {
|
||||
return register(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:arguments:)`
|
||||
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:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
public func register<T, A, B, C>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A, B, C) throws -> T) -> Definition<T, (A, B, C)> {
|
||||
return register(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:arguments:)`
|
||||
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:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
public func register<T, A, B, C, D>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A, B, C, D) throws -> T) -> Definition<T, (A, B, C, D)> {
|
||||
return register(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:arguments:)`
|
||||
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:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
public func register<T, A, B, C, D, E>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A, B, C, D, E) throws -> T) -> Definition<T, (A, B, C, D, E)> {
|
||||
return register(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:arguments:)`
|
||||
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:arguments:)`
|
||||
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(_:type:tag:factory:)`
|
||||
public func register<T, A, B, C, D, E, F>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A, B, C, D, E, F) throws -> T) -> Definition<T, (A, B, C, D, E, F)> {
|
||||
return register(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:arguments:)`
|
||||
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:arguments:)`
|
||||
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)) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,245 @@
|
||||
//
|
||||
// DipUI
|
||||
//
|
||||
// Copyright (c) 2016 Ilya Puchka <ilyapuchka@gmail.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if (canImport(UIKit) || canImport(AppKit) || canImport(WatchKit)) && !SWIFT_PACKAGE
|
||||
|
||||
extension DependencyContainer {
|
||||
///Containers that will be used to resolve dependencies of instances, created by stroyboards.
|
||||
static public var uiContainers: [DependencyContainer] = {
|
||||
#if os(watchOS)
|
||||
swizzleAwakeWithContext
|
||||
#endif
|
||||
return []
|
||||
}()
|
||||
|
||||
/**
|
||||
Resolves dependencies of passed in instance.
|
||||
Use this method to resolve dependencies of object created by storyboard.
|
||||
The type of the instance should be registered in the container.
|
||||
|
||||
You should call this method only from implementation of `didInstantiateFromStoryboard(_:tag:)`
|
||||
of `StoryboardInstantiatable` protocol if you override its default implementation.
|
||||
|
||||
This method will do the same as `resolve(tag:) as T`, but instead of creating
|
||||
a new intance with a registered factory it will use passed in instance as a resolved instance.
|
||||
|
||||
- parameters:
|
||||
- instance: The object which dependencies should be resolved
|
||||
- tag: An optional tag used to register the type (`T`) in the container
|
||||
|
||||
**Example**:
|
||||
|
||||
```swift
|
||||
class ViewController: UIViewController, ServiceDelegate, StoryboardInstantiatable {
|
||||
var service: Service?
|
||||
|
||||
func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag?) throws {
|
||||
try container.resolveDependencies(of: self as ServiceDelegate, tag: "vc")
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceImp: Service {
|
||||
weak var delegate: ServiceDelegate?
|
||||
}
|
||||
|
||||
container.register(tag: "vc") { ViewController() }
|
||||
.resolvingProperties { container, controller in
|
||||
controller.service = try container.resolve() as Service
|
||||
controller.service.delegate = controller
|
||||
}
|
||||
|
||||
container.register { ServiceImp() as Service }
|
||||
```
|
||||
|
||||
- seealso: `register(_:type:tag:factory:)`, `didInstantiateFromStoryboard(_:tag:)`
|
||||
|
||||
*/
|
||||
public func resolveDependencies<T>(of instance: T, tag: Tag? = nil) throws {
|
||||
_ = try resolve(tag: tag) { (_: () throws -> T) in instance }
|
||||
}
|
||||
|
||||
/**
|
||||
Register storyboard type `T` which has to conform to `StoryboardInstantiatable` and associate it with an optional tag.
|
||||
|
||||
- parameters:
|
||||
- type: Storyboard type to register definition for.
|
||||
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
|
||||
|
||||
- returns: A registered definition.
|
||||
|
||||
- note: This method will register concrete types. If you need to register
|
||||
as abstract types you should use standard `register` method from Dip.
|
||||
You should cast the factory return type to the protocol you want to
|
||||
register it for (unless you want to register concrete type) or
|
||||
provide `type` parameter.
|
||||
|
||||
- seealso: `Definition`, `ComponentScope`, `DependencyTagConvertible`
|
||||
|
||||
**Example**:
|
||||
```swift
|
||||
// Register MyViewController
|
||||
container.register(storyboardType: MyViewController.self)
|
||||
// or
|
||||
container.register(tag: "myVC") { MyViewController() as MyViewControllerType }
|
||||
```
|
||||
*/
|
||||
public func register<T: NSObject>(storyboardType type: T.Type, tag: DependencyTagConvertible? = nil) -> Dip.Definition<T, ()> where T: StoryboardInstantiatable {
|
||||
return register(.unique, type: type, tag: tag, factory: { T() })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if os(watchOS)
|
||||
public protocol StoryboardInstantiatableType {}
|
||||
#else
|
||||
public typealias StoryboardInstantiatableType = NSObjectProtocol
|
||||
#endif
|
||||
|
||||
public protocol StoryboardInstantiatable: StoryboardInstantiatableType {
|
||||
|
||||
/**
|
||||
This method will be called if you set a `dipTag` attirbute on the object in a storyboard
|
||||
that conforms to `StoryboardInstantiatable` protocol.
|
||||
|
||||
- parameters:
|
||||
- tag: The tag value, that was set on the object in a storyboard
|
||||
- container: The `DependencyContainer` associated with storyboards
|
||||
|
||||
The type that implements `StoryboardInstantiatable` protocol should be registered in `UIStoryboard.container`.
|
||||
Default implementation of that method calls `resolveDependenciesOf(_:tag:)`
|
||||
and pass it `self` instance and the tag.
|
||||
|
||||
Usually you will not need to override the default implementation of this method
|
||||
if you registered the type of the instance as a concrete type in the container.
|
||||
Then you only need to add conformance to `StoryboardInstantiatable`.
|
||||
|
||||
You may want to override it if you want to add custom logic before/after resolving dependencies
|
||||
or you want to resolve the instance as implementation of some protocol which it conforms to.
|
||||
|
||||
- warning: This method will be called after `init?(coder:)` but before `awakeFromNib` method of `NSObject`.
|
||||
On watchOS this method will be called before `awakeWithContext(_:)`.
|
||||
|
||||
**Example**:
|
||||
|
||||
```swift
|
||||
extension MyViewController: SomeProtocol { ... }
|
||||
|
||||
extension MyViewController: StoryboardInstantiatable {
|
||||
func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag) throws {
|
||||
//resolve dependencies of the instance as SomeProtocol type
|
||||
try container.resolveDependencies(of: self as SomeProtocol, tag: tag)
|
||||
//do some additional setup here
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag?) throws
|
||||
|
||||
}
|
||||
|
||||
extension StoryboardInstantiatable {
|
||||
public func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag?) throws {
|
||||
try container.resolveDependencies(of: self, tag: tag)
|
||||
}
|
||||
}
|
||||
|
||||
#if os(iOS) || os(tvOS) || os(OSX)
|
||||
|
||||
#if os(iOS) || os(tvOS)
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
let DipTagAssociatedObjectKey = UnsafeMutablePointer<Int8>.allocate(capacity: 1)
|
||||
|
||||
extension NSObject {
|
||||
|
||||
///A string tag that will be used to resolve dependencies of this instance
|
||||
///if it implements `StoryboardInstantiatable` protocol.
|
||||
@objc private(set) public var dipTag: String? {
|
||||
get {
|
||||
return objc_getAssociatedObject(self, DipTagAssociatedObjectKey) as? String
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(self, DipTagAssociatedObjectKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
|
||||
guard let instantiatable = self as? StoryboardInstantiatable else { return }
|
||||
|
||||
let tag = dipTag.map(DependencyContainer.Tag.String)
|
||||
|
||||
for (index, container) in DependencyContainer.uiContainers.enumerated() {
|
||||
do {
|
||||
log("Trying to resolve \(type(of: self)) with UI container at index \(index)")
|
||||
try instantiatable.didInstantiateFromStoryboard(container, tag: tag)
|
||||
log("Resolved \(type(of: self))")
|
||||
return
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func log(_ message: Any) {
|
||||
if Dip.LogLevel.Errors.rawValue <= Dip.logLevel.rawValue {
|
||||
Dip.logger(logLevel, message)
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
import WatchKit
|
||||
|
||||
let swizzleAwakeWithContext: Void = {
|
||||
let originalSelector = #selector(WKInterfaceController.awake(withContext:))
|
||||
let swizzledSelector = #selector(WKInterfaceController.dip_awake(withContext:))
|
||||
|
||||
guard let originalMethod = class_getInstanceMethod(WKInterfaceController.self, originalSelector),
|
||||
let swizzledMethod = class_getInstanceMethod(WKInterfaceController.self, swizzledSelector) else { return }
|
||||
|
||||
let didAddMethod = class_addMethod(WKInterfaceController.self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
|
||||
|
||||
if didAddMethod {
|
||||
class_replaceMethod(WKInterfaceController.self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
|
||||
} else {
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod)
|
||||
}
|
||||
}()
|
||||
|
||||
extension WKInterfaceController: StoryboardInstantiatableType {
|
||||
|
||||
@objc func dip_awake(withContext context: AnyObject?) {
|
||||
defer { self.dip_awake(withContext: context) }
|
||||
guard let instantiatable = self as? StoryboardInstantiatable else { return }
|
||||
|
||||
for container in DependencyContainer.uiContainers {
|
||||
guard let _ = try? instantiatable.didInstantiateFromStoryboard(container, tag: nil) else { continue }
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -27,8 +27,6 @@ protocol TypeForwardingDefinition: DefinitionType {
|
||||
func doesImplements(type aType: Any.Type) -> Bool
|
||||
}
|
||||
|
||||
#if swift(>=3.0)
|
||||
|
||||
extension Definition {
|
||||
|
||||
/**
|
||||
@@ -84,14 +82,12 @@ extension Definition {
|
||||
}
|
||||
|
||||
///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 {
|
||||
@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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extension DependencyContainer {
|
||||
|
||||
func _register<T, U, F>(definition aDefinition: Definition<T, U>, type: F.Type, tag: DependencyTagConvertible? = nil) -> Definition<F, U> {
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
//
|
||||
// Dip
|
||||
//
|
||||
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if !swift(>=3.0)
|
||||
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public func implements<F>(type: F.Type, tag: DependencyTagConvertible? = nil, resolvingProperties: (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
|
||||
public func implements<A, B>(a: A.Type, _ b: B.Type) -> Definition {
|
||||
return implements(a).implements(b)
|
||||
}
|
||||
|
||||
///Registers definition for types passed as parameters
|
||||
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
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+6
-9
@@ -30,9 +30,11 @@ public enum LogLevel: Int {
|
||||
|
||||
public var logLevel: LogLevel = .Errors
|
||||
|
||||
public var logger: (LogLevel, Any) -> Void = { print($1) }
|
||||
|
||||
func log(level logLevel: LogLevel, _ message: Any) {
|
||||
guard logLevel.rawValue <= Dip.logLevel.rawValue else { return }
|
||||
print(message)
|
||||
logger(logLevel, message)
|
||||
}
|
||||
|
||||
///Internal protocol used to unwrap optional values.
|
||||
@@ -46,11 +48,6 @@ extension Optional: BoxType {
|
||||
}
|
||||
}
|
||||
|
||||
extension ImplicitlyUnwrappedOptional: BoxType {
|
||||
var unboxed: Any? {
|
||||
return self ?? nil
|
||||
}
|
||||
}
|
||||
|
||||
class Box<T> {
|
||||
var unboxed: T
|
||||
@@ -70,10 +67,10 @@ class WeakBox<T>: WeakBoxType {
|
||||
}
|
||||
|
||||
init(_ value: T) {
|
||||
#if !_runtime(_ObjC) || !swift(>=3.0)
|
||||
weak var value: AnyObject? = value as? AnyObject
|
||||
#else
|
||||
#if _runtime(_ObjC)
|
||||
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))")
|
||||
|
||||
@@ -26,7 +26,7 @@ import XCTest
|
||||
@testable import Dip
|
||||
|
||||
private protocol Server: class {
|
||||
weak var client: Client! {get}
|
||||
var client: Client! {get}
|
||||
var anotherClient: Client! {get set}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ private class ServerImp: Server {
|
||||
|
||||
weak var anotherClient: Client!
|
||||
|
||||
weak var _optionalProperty = InjectedWeak<AnyObject>(required: false)
|
||||
var _optionalProperty = InjectedWeak<AnyObject>(required: false)
|
||||
}
|
||||
|
||||
private class ClientImp: Client {
|
||||
|
||||
@@ -55,7 +55,9 @@ class AutoWiringTests: XCTestCase {
|
||||
("testThatItCanResolveWithAutoWiring", testThatItCanResolveWithAutoWiring),
|
||||
("testThatItUsesAutoWireFactoryWithMostNumberOfArguments", testThatItUsesAutoWireFactoryWithMostNumberOfArguments),
|
||||
("testThatItThrowsAmbiguityErrorWhenUsingAutoWire", testThatItThrowsAmbiguityErrorWhenUsingAutoWire),
|
||||
("testThatItFirstTriesToUseTaggedFactoriesWhenUsingAutoWire", testThatItFirstTriesToUseTaggedFactoriesWhenUsingAutoWire),
|
||||
("testThatItUsesAutoWireFactoryWithMostNumberOfArguments", testThatItUsesAutoWireFactoryWithMostNumberOfArguments),
|
||||
("testThatItPrefersTaggedFactoryWithDifferentNumberOfArgumentsWhenUsingAutoWire", testThatItPrefersTaggedFactoryWithDifferentNumberOfArgumentsWhenUsingAutoWire),
|
||||
("testThatItPrefersTaggedFactoryWithDifferentTypesOfArgumentsWhenUsingAutoWire", testThatItPrefersTaggedFactoryWithDifferentTypesOfArgumentsWhenUsingAutoWire),
|
||||
("testThatItFallbackToNotTaggedFactoryWhenUsingAutoWire", testThatItFallbackToNotTaggedFactoryWhenUsingAutoWire),
|
||||
("testThatItDoesNotTryToUseAutoWiringWhenCallingResolveWithArguments", testThatItDoesNotTryToUseAutoWiringWhenCallingResolveWithArguments),
|
||||
("testThatItDoesNotUseAutoWiringWhenFailedToResolveLowLevelDependency", testThatItDoesNotUseAutoWiringWhenFailedToResolveLowLevelDependency),
|
||||
@@ -110,7 +112,7 @@ class AutoWiringTests: XCTestCase {
|
||||
//2 args
|
||||
var factoryWithMostNumberOfArgumentsCalled = false
|
||||
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
|
||||
.resolvingProperties { _ in
|
||||
.resolvingProperties { _,_ in
|
||||
factoryWithMostNumberOfArgumentsCalled = true
|
||||
}
|
||||
|
||||
@@ -146,7 +148,7 @@ class AutoWiringTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
func testThatItFirstTriesToUseTaggedFactoriesWhenUsingAutoWire() {
|
||||
func testThatItPrefersTaggedFactoryWithDifferentNumberOfArgumentsWhenUsingAutoWire() {
|
||||
//given
|
||||
|
||||
//1 arg
|
||||
@@ -162,7 +164,7 @@ class AutoWiringTests: XCTestCase {
|
||||
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
|
||||
|
||||
//2 arg tagged
|
||||
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }.resolvingProperties { _ in
|
||||
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }.resolvingProperties { _,_ in
|
||||
taggedFactoryWithMostNumberOfArgumentsCalled = true
|
||||
}
|
||||
|
||||
@@ -176,12 +178,37 @@ class AutoWiringTests: XCTestCase {
|
||||
XCTAssertTrue(taggedFactoryWithMostNumberOfArgumentsCalled)
|
||||
}
|
||||
|
||||
func testThatItPrefersTaggedFactoryWithDifferentTypesOfArgumentsWhenUsingAutoWire() {
|
||||
//given
|
||||
|
||||
//1 arg
|
||||
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
|
||||
|
||||
//2 args
|
||||
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
|
||||
|
||||
//1 arg tagged
|
||||
var taggedFactoryCalled = false
|
||||
container.register(tag: "tag") { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }.resolvingProperties { _,_ in
|
||||
taggedFactoryCalled = true
|
||||
}
|
||||
|
||||
container.register() { ServiceImp1() as Service }
|
||||
container.register { ServiceImp2() }
|
||||
|
||||
//when
|
||||
let _ = try! container.resolve(tag: "tag") as AutoWiredClient
|
||||
|
||||
//then
|
||||
XCTAssertTrue(taggedFactoryCalled)
|
||||
}
|
||||
|
||||
func testThatItFallbackToNotTaggedFactoryWhenUsingAutoWire() {
|
||||
//given
|
||||
|
||||
//1 arg
|
||||
var notTaggedFactoryWithMostNumberOfArgumentsCalled = false
|
||||
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }.resolvingProperties { _ in
|
||||
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }.resolvingProperties { _,_ in
|
||||
notTaggedFactoryWithMostNumberOfArgumentsCalled = true
|
||||
}
|
||||
|
||||
@@ -440,17 +467,9 @@ class AutoWiringTests: XCTestCase {
|
||||
AssertNoThrow(expression: resolved = try container.resolve() as AutoWiredClient?)
|
||||
XCTAssertNotNil(resolved)
|
||||
|
||||
//when
|
||||
AssertNoThrow(expression: resolved = try container.resolve() as AutoWiredClient!)
|
||||
XCTAssertNotNil(resolved)
|
||||
|
||||
//when
|
||||
AssertNoThrow(expression: resolved = try container.resolve(tag: "tag") as AutoWiredClient?)
|
||||
XCTAssertNotNil(resolved)
|
||||
|
||||
//when
|
||||
AssertNoThrow(expression: resolved = try container.resolve(tag: "tag") as AutoWiredClient!)
|
||||
XCTAssertNotNil(resolved)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -301,23 +301,17 @@ class ComponentScopeTests: XCTestCase {
|
||||
|
||||
func testThatItReusesResolvedInstanceWhenResolvingOptional() {
|
||||
var otherService: Service!
|
||||
var impOtherService: Service!
|
||||
var anyOtherService: Any!
|
||||
var anyImpOtherService: Any!
|
||||
|
||||
|
||||
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)
|
||||
anyImpOtherService = try! container.resolve((Service!).self)
|
||||
}
|
||||
|
||||
let service = try! container.resolve() as Service
|
||||
XCTAssertTrue(otherService as! ServiceImp1 === service as! ServiceImp1)
|
||||
XCTAssertTrue(impOtherService as! ServiceImp1 === service as! ServiceImp1)
|
||||
XCTAssertTrue(anyOtherService as! ServiceImp1 === service as! ServiceImp1)
|
||||
XCTAssertTrue(anyImpOtherService as! ServiceImp1 === service as! ServiceImp1)
|
||||
}
|
||||
|
||||
func testThatItHoldsWeakReferenceToWeakSingletonInstance() {
|
||||
|
||||
@@ -63,7 +63,7 @@ class ContextTests: XCTestCase {
|
||||
XCTAssertTrue(self.container.context.resolvingType == Service.self)
|
||||
let _ = try self.container.resolve() as ServiceImp1
|
||||
return ServiceImp1() as Service
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertTrue(self.container.context.resolvingType == Service.self)
|
||||
let _ = try self.container.resolve() as ServiceImp1
|
||||
}
|
||||
@@ -71,7 +71,7 @@ class ContextTests: XCTestCase {
|
||||
container.register { () -> ServiceImp1 in
|
||||
XCTAssertTrue(self.container.context.resolvingType == ServiceImp1.self)
|
||||
return ServiceImp1()
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertTrue(self.container.context.resolvingType == ServiceImp1.self)
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ class ContextTests: XCTestCase {
|
||||
XCTAssertNil(self.container.context.injectedInType)
|
||||
let _ = try self.container.resolve() as ServiceImp1
|
||||
return ServiceImp1() as Service
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertNil(self.container.context.injectedInType)
|
||||
let _ = try self.container.resolve() as ServiceImp1
|
||||
}
|
||||
@@ -91,7 +91,7 @@ class ContextTests: XCTestCase {
|
||||
container.register { () -> ServiceImp1 in
|
||||
XCTAssertTrue(self.container.context.injectedInType == Service.self)
|
||||
return ServiceImp1()
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertTrue(self.container.context.injectedInType == Service.self)
|
||||
}
|
||||
|
||||
@@ -104,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
|
||||
}.resolvingProperties { _ 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
|
||||
@@ -114,7 +114,7 @@ class ContextTests: XCTestCase {
|
||||
XCTAssertNotNil(self.container.context.tag)
|
||||
XCTAssertTrue(DependencyContainer.Tag.String("otherTag") ~= self.container.context.tag!)
|
||||
return ServiceImp1()
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertNotNil(self.container.context.tag)
|
||||
XCTAssertTrue(DependencyContainer.Tag.String("otherTag") ~= self.container.context.tag!)
|
||||
}
|
||||
@@ -135,7 +135,7 @@ class ContextTests: XCTestCase {
|
||||
XCTAssertTrue(DependencyContainer.Tag.String("injectedTag") ~= self.container.context.tag!)
|
||||
}
|
||||
return ServiceImp2()
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
if self.container.context.injectedInProperty == "injectedNilTag" {
|
||||
XCTAssertNil(self.container.context.tag)
|
||||
}
|
||||
@@ -149,7 +149,7 @@ class ContextTests: XCTestCase {
|
||||
XCTAssertNotNil(self.container.context.tag)
|
||||
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
|
||||
return ServiceImp2()
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertNotNil(self.container.context.tag)
|
||||
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
|
||||
}
|
||||
@@ -160,14 +160,14 @@ class ContextTests: XCTestCase {
|
||||
func testThatContextStoresTheTagPassedToResolveWhenAutoWiring() {
|
||||
container.register { (_: ServiceImp1) -> Service in
|
||||
return ServiceImp1() as Service
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
}
|
||||
|
||||
container.register { () -> ServiceImp1 in
|
||||
XCTAssertNotNil(self.container.context.tag)
|
||||
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
|
||||
return ServiceImp1()
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertNotNil(self.container.context.tag)
|
||||
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
|
||||
}
|
||||
@@ -181,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
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertNotNil(self.container.context.tag)
|
||||
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
|
||||
let _ = try self.container.resolve() as ServiceImp1
|
||||
@@ -190,7 +190,7 @@ class ContextTests: XCTestCase {
|
||||
container.register { () -> ServiceImp1 in
|
||||
XCTAssertNil(self.container.context.tag)
|
||||
return ServiceImp1()
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertNil(self.container.context.tag)
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ class ContextTests: XCTestCase {
|
||||
XCTAssertNotNil(self.container.context.injectedInProperty)
|
||||
XCTAssertTrue(names.contains(self.container.context.injectedInProperty!))
|
||||
return ServiceImp2()
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertNotNil(self.container.context.injectedInProperty)
|
||||
XCTAssertTrue(names.contains(self.container.context.injectedInProperty!))
|
||||
}
|
||||
@@ -239,7 +239,7 @@ class ContextTests: XCTestCase {
|
||||
XCTAssertTrue(self.container.context.resolvingType == Service.self)
|
||||
let _ = try self.container.resolve() as ServiceImp1
|
||||
return ServiceImp1() as Service
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertTrue(self.container.context.resolvingType == Service.self)
|
||||
let _ = try self.container.resolve() as ServiceImp1
|
||||
}
|
||||
@@ -247,7 +247,7 @@ class ContextTests: XCTestCase {
|
||||
collaborator.register { () -> ServiceImp1 in
|
||||
XCTAssertTrue(collaborator.context.resolvingType == ServiceImp1.self)
|
||||
return ServiceImp1()
|
||||
}.resolvingProperties { _ in
|
||||
}.resolvingProperties { _,_ in
|
||||
XCTAssertTrue(collaborator.context.resolvingType == ServiceImp1.self)
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,6 @@ class DefinitionTests: XCTestCase {
|
||||
let def = Definition<Service, ()>(scope: .unique) { ServiceImp() as Service }
|
||||
|
||||
XCTAssertTrue(def.implementingTypes.contains(where: { $0 == Service?.self }))
|
||||
XCTAssertTrue(def.implementingTypes.contains(where: { $0 == Service!.self }))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+155
-30
@@ -30,7 +30,7 @@ private class ServiceImp1: Service { }
|
||||
private class ServiceImp2: Service { }
|
||||
|
||||
private protocol Server: class {
|
||||
weak var client: Client! { get }
|
||||
var client: Client! { get }
|
||||
}
|
||||
private protocol Client: class {
|
||||
var server: Server! { get }
|
||||
@@ -70,6 +70,7 @@ class DipTests: XCTestCase {
|
||||
("testThatCollaboratingWithSelfIsIgnored", testThatCollaboratingWithSelfIsIgnored),
|
||||
("testThatCollaboratingContainersAreWeakReferences", testThatCollaboratingContainersAreWeakReferences),
|
||||
("testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer", testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer),
|
||||
("testThatItCanHandleSeparateContainersAndTheirCollaboration", testThatItCanHandleSeparateContainersAndTheirCollaboration)
|
||||
]
|
||||
}()
|
||||
|
||||
@@ -123,12 +124,6 @@ class DipTests: XCTestCase {
|
||||
|
||||
//then
|
||||
XCTAssertTrue(optService is ServiceImp1)
|
||||
|
||||
//and when
|
||||
let impService = try! container.resolve((Service!).self)
|
||||
|
||||
//then
|
||||
XCTAssertTrue(impService is ServiceImp1)
|
||||
}
|
||||
|
||||
func testThatItResolvesInstanceRegisteredWithTag() {
|
||||
@@ -152,12 +147,6 @@ class DipTests: XCTestCase {
|
||||
|
||||
//then
|
||||
XCTAssertTrue(optService is ServiceImp1)
|
||||
|
||||
//and when
|
||||
let impService = try! container.resolve((Service!).self, tag: "service")
|
||||
|
||||
//then
|
||||
XCTAssertTrue(impService is ServiceImp1)
|
||||
}
|
||||
|
||||
func testThatItResolvesDifferentInstancesRegisteredForDifferentTags() {
|
||||
@@ -188,14 +177,6 @@ class DipTests: XCTestCase {
|
||||
//then
|
||||
XCTAssertTrue(optService1 is ServiceImp1)
|
||||
XCTAssertTrue(optService2 is ServiceImp2)
|
||||
|
||||
//and when
|
||||
let impService1 = try! container.resolve((Service!).self, tag: "service1")
|
||||
let impService2 = try! container.resolve((Service!).self, tag: "service2")
|
||||
|
||||
//then
|
||||
XCTAssertTrue(impService1 is ServiceImp1)
|
||||
XCTAssertTrue(impService2 is ServiceImp2)
|
||||
}
|
||||
|
||||
func testThatNewRegistrationOverridesPreviousRegistration() {
|
||||
@@ -241,12 +222,6 @@ class DipTests: XCTestCase {
|
||||
XCTAssertTrue(resolveDependenciesCalled)
|
||||
|
||||
resolveDependenciesCalled = false
|
||||
|
||||
//and when
|
||||
let _ = try! container.resolve((Service!).self)
|
||||
|
||||
//then
|
||||
XCTAssertTrue(resolveDependenciesCalled)
|
||||
}
|
||||
|
||||
func testThatItThrowsErrorIfCanNotFindDefinitionForType() {
|
||||
@@ -573,12 +548,12 @@ class DipTests: XCTestCase {
|
||||
}.implements(Service.self)
|
||||
|
||||
container.register(tag: "tag") { ServiceImp2() as Service }
|
||||
.resolvingProperties { _ in
|
||||
.resolvingProperties { _,_ in
|
||||
createdService2 = true
|
||||
}
|
||||
|
||||
container.register { (arg: String) in ServiceImp1() }
|
||||
.resolvingProperties { _ in
|
||||
.resolvingProperties { _,_ in
|
||||
createdService3 = true
|
||||
}
|
||||
|
||||
@@ -658,6 +633,7 @@ extension DipTests {
|
||||
//given
|
||||
let collaborator = DependencyContainer()
|
||||
collaborator.register { ResolvableService() as Service }
|
||||
container.register { "something" }
|
||||
|
||||
//when
|
||||
container.collaborate(with: collaborator)
|
||||
@@ -665,13 +641,14 @@ extension DipTests {
|
||||
//then
|
||||
AssertNoThrow(expression: try container.resolve() as Service)
|
||||
AssertNoThrow(expression: try container.resolve(Service.self))
|
||||
AssertNoThrow(expression: try collaborator.resolve() as String)
|
||||
AssertNoThrow(expression: try collaborator.resolve(String.self))
|
||||
}
|
||||
|
||||
func testThatCollaboratingWithSelfIsIgnored() {
|
||||
let collaborator = DependencyContainer()
|
||||
collaborator.collaborate(with: collaborator)
|
||||
XCTAssertTrue(collaborator._collaborators.isEmpty, "Container should not collaborate with itself")
|
||||
|
||||
}
|
||||
|
||||
func testThatCollaboratingContainersAreWeakReferences() {
|
||||
@@ -730,4 +707,152 @@ extension DipTests {
|
||||
XCTAssertTrue(client?.server === (client as? ClientImp)?.anotherServer)
|
||||
}
|
||||
|
||||
func testThatCollaborationReferencesAreRecursivelyUpdate() {
|
||||
let container = DependencyContainer()
|
||||
container.register(.singleton){ ResolvableService() as Service }
|
||||
|
||||
//when
|
||||
let collaborator1 = DependencyContainer()
|
||||
let collaborator2 = DependencyContainer()
|
||||
let collaborator3 = DependencyContainer()
|
||||
let collaborator4 = DependencyContainer()
|
||||
|
||||
collaborator1.collaborate(with: container)
|
||||
XCTAssertTrue(collaborator1.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
|
||||
|
||||
collaborator2.collaborate(with: container)
|
||||
XCTAssertTrue(collaborator2.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
|
||||
|
||||
collaborator3.collaborate(with: collaborator1)
|
||||
XCTAssertTrue(collaborator3.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
|
||||
|
||||
collaborator4.collaborate(with: collaborator2)
|
||||
XCTAssertTrue(collaborator4.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
|
||||
|
||||
let service1 = try! collaborator1.resolve() as Service
|
||||
let service2 = try! collaborator2.resolve() as Service
|
||||
let service3 = try! collaborator3.resolve() as Service
|
||||
let service4 = try! collaborator4.resolve() as Service
|
||||
let serviceRoot = try! container.resolve() as Service
|
||||
|
||||
XCTAssertTrue(service1 === service2)
|
||||
XCTAssertTrue(service1 === service3)
|
||||
XCTAssertTrue(service1 === service4)
|
||||
|
||||
XCTAssertTrue(service1 === serviceRoot)
|
||||
XCTAssertTrue(service2 === serviceRoot)
|
||||
XCTAssertTrue(service3 === serviceRoot)
|
||||
XCTAssertTrue(service4 === serviceRoot)
|
||||
}
|
||||
|
||||
class RootService {}
|
||||
class ServiceClient {
|
||||
let name: String
|
||||
let service: RootService
|
||||
init(name: String, service: RootService) {
|
||||
self.name = name
|
||||
self.service = service
|
||||
}
|
||||
}
|
||||
|
||||
func testThatContainersShareTheirSingletonsOnlyWithCollaborators() {
|
||||
let container = DependencyContainer()
|
||||
container.register(.singleton) { RootService() }
|
||||
|
||||
let collaborator1 = DependencyContainer()
|
||||
collaborator1.register(.singleton) {
|
||||
ServiceClient(name: "1", service: $0)
|
||||
}
|
||||
|
||||
let collaborator2 = DependencyContainer()
|
||||
collaborator2.register(.singleton) {
|
||||
ServiceClient(name: "2", service: $0)
|
||||
}
|
||||
|
||||
collaborator1.collaborate(with: container)
|
||||
collaborator2.collaborate(with: container)
|
||||
|
||||
let client2 = try! collaborator2.resolve() as ServiceClient
|
||||
let client1 = try! collaborator1.resolve() as ServiceClient
|
||||
|
||||
XCTAssertEqual(client1.name, "1")
|
||||
XCTAssertEqual(client2.name, "2")
|
||||
XCTAssertTrue(client1.service === client2.service)
|
||||
}
|
||||
|
||||
func testThatContainerAutowireBeforeCollaboration() {
|
||||
let container = DependencyContainer()
|
||||
container.register(.singleton) { RootService() }
|
||||
|
||||
let collaborator1 = DependencyContainer()
|
||||
collaborator1.register(.singleton) {
|
||||
ServiceClient(name: "1", service: $0)
|
||||
}
|
||||
|
||||
let collaborator2 = DependencyContainer()
|
||||
collaborator2.register(.singleton) {
|
||||
ServiceClient(name: "2", service: $0)
|
||||
}
|
||||
|
||||
collaborator1.collaborate(with: container, collaborator2)
|
||||
collaborator2.collaborate(with: container, collaborator1)
|
||||
|
||||
let client2 = try! collaborator2.resolve() as ServiceClient
|
||||
let client1 = try! collaborator1.resolve() as ServiceClient
|
||||
|
||||
XCTAssertEqual(client1.name, "1")
|
||||
XCTAssertEqual(client2.name, "2")
|
||||
XCTAssertTrue(client1.service === client2.service)
|
||||
}
|
||||
}
|
||||
|
||||
class Manager {}
|
||||
class AnotherManager {}
|
||||
|
||||
class Object {
|
||||
let manager: Manager?
|
||||
|
||||
init(with container: DependencyContainer) {
|
||||
self.manager = try? container.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
class Owner {
|
||||
var manager: Manager?
|
||||
}
|
||||
|
||||
extension DipTests {
|
||||
func testThatItCanHandleSeparateContainersAndTheirCollaboration() {
|
||||
let container = self.container
|
||||
|
||||
let anotherContainer = DependencyContainer()
|
||||
anotherContainer.register { Object(with: anotherContainer) }
|
||||
|
||||
container.collaborate(with: anotherContainer)
|
||||
|
||||
container
|
||||
.register { Owner() }
|
||||
.resolvingProperties { $1.manager = try $0.resolve() }
|
||||
|
||||
container.register(.singleton) { AnotherManager() }
|
||||
container.register(.singleton) { Manager() }
|
||||
|
||||
let manager: Manager? = try? container.resolve()
|
||||
let another: AnotherManager? = try? container.resolve()
|
||||
var owner: Owner? = try? container.resolve(arguments: 1, "")
|
||||
|
||||
let object: Object? = try? container.resolve()
|
||||
owner = try? container.resolve()
|
||||
|
||||
let nonNilValues: [Any?] = [another, manager, owner, object, object?.manager]
|
||||
nonNilValues.forEach { XCTAssertNotNil($0) }
|
||||
|
||||
XCTAssertTrue(
|
||||
owner?.manager
|
||||
.flatMap { value in
|
||||
manager.flatMap { $0 === value }
|
||||
}
|
||||
?? false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
//
|
||||
// DipUI
|
||||
//
|
||||
// Copyright (c) 2016 Ilya Puchka <ilyapuchka@gmail.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if (canImport(UIKit) || canImport(AppKit)) && !SWIFT_PACKAGE
|
||||
|
||||
import XCTest
|
||||
@testable import Dip
|
||||
|
||||
#if canImport(UIKit)
|
||||
import UIKit
|
||||
typealias Storyboard = UIStoryboard
|
||||
typealias ViewController = UIViewController
|
||||
typealias StoryboardName = String
|
||||
|
||||
extension UIStoryboard {
|
||||
@nonobjc
|
||||
@discardableResult func instantiateViewControllerWithIdentifier(_ identifier: String) -> UIViewController {
|
||||
return instantiateViewController(withIdentifier: identifier)
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
import AppKit
|
||||
typealias Storyboard = NSStoryboard
|
||||
typealias ViewController = NSViewController
|
||||
typealias StoryboardName = NSStoryboard.Name
|
||||
|
||||
extension NSStoryboard {
|
||||
@discardableResult func instantiateViewControllerWithIdentifier(_ identifier: String) -> NSViewController {
|
||||
return instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(identifier)) as! NSViewController
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
let storyboardName: StoryboardName = "UIStoryboard"
|
||||
#elseif os(tvOS)
|
||||
let storyboardName: StoryboardName = "TVStoryboard"
|
||||
#else
|
||||
let storyboardName: StoryboardName = StoryboardName("NSStoryboard")
|
||||
#endif
|
||||
|
||||
class DipViewController: ViewController, StoryboardInstantiatable {}
|
||||
class NilTagViewController: ViewController, StoryboardInstantiatable {}
|
||||
|
||||
class DipUITests: XCTestCase {
|
||||
|
||||
let storyboard: Storyboard = {
|
||||
let bundle = Bundle(for: DipUITests.self)
|
||||
return Storyboard(name: storyboardName, bundle: bundle)
|
||||
}()
|
||||
|
||||
func testThatViewControllerHasDipTagProperty() {
|
||||
let viewController = storyboard.instantiateViewControllerWithIdentifier("DipViewController")
|
||||
XCTAssertEqual(viewController.dipTag, "vc")
|
||||
}
|
||||
|
||||
func testThatItDoesNotResolveIfContainerIsNotSet() {
|
||||
let container = DependencyContainer()
|
||||
container.register(tag: "vc") { ViewController() }
|
||||
.resolvingProperties { _, _ in
|
||||
XCTFail("Should not resolve when container is not set.")
|
||||
}
|
||||
|
||||
storyboard.instantiateViewControllerWithIdentifier("DipViewController")
|
||||
}
|
||||
|
||||
func testThatItDoesNotResolveIfTagIsNotSet() {
|
||||
let container = DependencyContainer()
|
||||
container.register(tag: "vc") { ViewController() }
|
||||
.resolvingProperties { _, _ in
|
||||
XCTFail("Should not resolve when container is not set.")
|
||||
}
|
||||
|
||||
DependencyContainer.uiContainers = [container]
|
||||
storyboard.instantiateViewControllerWithIdentifier("ViewController")
|
||||
}
|
||||
|
||||
func testThatItResolvesIfContainerAndStringTagAreSet() {
|
||||
var resolved = false
|
||||
let container = DependencyContainer()
|
||||
container.register(storyboardType: DipViewController.self, tag: "vc")
|
||||
.resolvingProperties { _, _ in
|
||||
resolved = true
|
||||
}
|
||||
|
||||
DependencyContainer.uiContainers = [container]
|
||||
storyboard.instantiateViewControllerWithIdentifier("DipViewController")
|
||||
XCTAssertTrue(resolved, "Should resolve when container and tag are set.")
|
||||
}
|
||||
|
||||
func testThatItResolvesIfContainerAndNilTagAreSet() {
|
||||
var resolved = false
|
||||
let container = DependencyContainer()
|
||||
container.register(storyboardType: NilTagViewController.self)
|
||||
.resolvingProperties { _, _ in
|
||||
resolved = true
|
||||
}
|
||||
|
||||
DependencyContainer.uiContainers = [container]
|
||||
storyboard.instantiateViewControllerWithIdentifier("NilTagViewController")
|
||||
XCTAssertTrue(resolved, "Should resolve when container and nil tag are set.")
|
||||
}
|
||||
|
||||
func testThatItDoesNotResolveIfTagDoesNotMatch() {
|
||||
let container = DependencyContainer()
|
||||
container.register(storyboardType: DipViewController.self, tag: "wrong tag")
|
||||
.resolvingProperties { _, _ in
|
||||
XCTFail("Should not resolve when container is not set.")
|
||||
}
|
||||
|
||||
DependencyContainer.uiContainers = [container]
|
||||
storyboard.instantiateViewControllerWithIdentifier("DipViewController")
|
||||
}
|
||||
|
||||
func testThatItResolvesWithDefinitionWithNoTag() {
|
||||
var resolved = false
|
||||
let container = DependencyContainer()
|
||||
container.register(storyboardType: DipViewController.self)
|
||||
.resolvingProperties { _, _ in
|
||||
resolved = true
|
||||
}
|
||||
|
||||
DependencyContainer.uiContainers = [container]
|
||||
storyboard.instantiateViewControllerWithIdentifier("DipViewController")
|
||||
XCTAssertTrue(resolved, "Should fallback to definition with no tag.")
|
||||
}
|
||||
|
||||
func testThatItIteratesUIContainers() {
|
||||
var resolved = false
|
||||
let container1 = DependencyContainer()
|
||||
let container2 = DependencyContainer()
|
||||
container2.register(storyboardType: DipViewController.self, tag: "vc")
|
||||
.resolvingProperties { container, _ in
|
||||
XCTAssertTrue(container === container2)
|
||||
resolved = true
|
||||
}
|
||||
|
||||
DependencyContainer.uiContainers = [container1, container2]
|
||||
storyboard.instantiateViewControllerWithIdentifier("DipViewController")
|
||||
XCTAssertTrue(resolved, "Should resolve using second container")
|
||||
}
|
||||
}
|
||||
|
||||
protocol SomeService: class {
|
||||
var delegate: SomeServiceDelegate? { get set }
|
||||
}
|
||||
protocol SomeServiceDelegate: class { }
|
||||
class SomeServiceImp: SomeService {
|
||||
weak var delegate: SomeServiceDelegate?
|
||||
init(delegate: SomeServiceDelegate) {
|
||||
self.delegate = delegate
|
||||
}
|
||||
init(){}
|
||||
}
|
||||
|
||||
protocol OtherService: class {
|
||||
var delegate: OtherServiceDelegate? { get set }
|
||||
}
|
||||
protocol OtherServiceDelegate: class {}
|
||||
class OtherServiceImp: OtherService {
|
||||
weak var delegate: OtherServiceDelegate?
|
||||
init(delegate: OtherServiceDelegate){
|
||||
self.delegate = delegate
|
||||
}
|
||||
init(){}
|
||||
}
|
||||
|
||||
|
||||
protocol SomeScreen: class {
|
||||
var someService: SomeService? { get set }
|
||||
var otherService: OtherService? { get set }
|
||||
}
|
||||
|
||||
class ViewControllerImp: SomeScreen, SomeServiceDelegate, OtherServiceDelegate {
|
||||
var someService: SomeService?
|
||||
var otherService: OtherService?
|
||||
init(){}
|
||||
}
|
||||
|
||||
extension DipUITests {
|
||||
|
||||
func testThatItDoesNotCreateNewInstanceWhenResolvingDependenciesOfExternalInstance() {
|
||||
let container = DependencyContainer()
|
||||
|
||||
//given
|
||||
var factoryCalled = false
|
||||
container.register(.shared) { () -> SomeScreen in
|
||||
factoryCalled = true
|
||||
return ViewControllerImp() as SomeScreen
|
||||
}
|
||||
|
||||
//when
|
||||
let screen = ViewControllerImp()
|
||||
try! container.resolveDependencies(of: screen as SomeScreen)
|
||||
|
||||
//then
|
||||
XCTAssertFalse(factoryCalled, "Container should not create new instance when resolving dependencies of external instance.")
|
||||
}
|
||||
|
||||
func testThatItResolvesInstanceThatImplementsSeveralProtocols() {
|
||||
let container = DependencyContainer()
|
||||
|
||||
//given
|
||||
container.register(.shared) { ViewControllerImp() as SomeScreen }
|
||||
.resolvingProperties { container, resolved in
|
||||
|
||||
//manually provide resolved instance for the delegate properties
|
||||
resolved.someService = try container.resolve() as SomeService
|
||||
resolved.someService?.delegate = resolved as? SomeServiceDelegate
|
||||
resolved.otherService = try container.resolve(arguments: resolved as! OtherServiceDelegate) as OtherService
|
||||
}
|
||||
|
||||
container.register(.shared) { SomeServiceImp() as SomeService }
|
||||
container.register(.shared) { OtherServiceImp(delegate: $0) as OtherService }
|
||||
|
||||
//when
|
||||
let screen = try! container.resolve() as SomeScreen
|
||||
|
||||
//then
|
||||
XCTAssertNotNil(screen.someService)
|
||||
XCTAssertNotNil(screen.otherService)
|
||||
|
||||
XCTAssertTrue(screen.someService?.delegate === screen)
|
||||
XCTAssertTrue(screen.otherService?.delegate === screen)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -30,6 +30,25 @@ private protocol ForwardedType: class { }
|
||||
private class ServiceImp1: NSObject, Service, ForwardedType { }
|
||||
private class ServiceImp2: NSObject, Service, ForwardedType { }
|
||||
|
||||
private protocol Dependency {}
|
||||
private struct DependencyImpl: Dependency {}
|
||||
private class DependencyRefImpl: Dependency {}
|
||||
|
||||
private struct DependencyClient {
|
||||
let dep: Dependency
|
||||
init(dependency: Dependency) {
|
||||
self.dep = dependency
|
||||
}
|
||||
}
|
||||
|
||||
private struct OptionalDependencyClient {
|
||||
let dep: Dependency?
|
||||
init(dependency: Dependency?) {
|
||||
self.dep = dependency
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TypeForwardingTests: XCTestCase {
|
||||
|
||||
let container = DependencyContainer()
|
||||
@@ -44,6 +63,7 @@ class TypeForwardingTests: XCTestCase {
|
||||
("testThatItCallsResolvedDependenciesBlockProvidedAfterRegistrationWhenResolvingByTypeForwarding",testThatItCallsResolvedDependenciesBlockProvidedAfterRegistrationWhenResolvingByTypeForwarding),
|
||||
("testThatItFallbackToDefinitionWithNoTagWhenResolvingInstanceByTypeForwarding", testThatItFallbackToDefinitionWithNoTagWhenResolvingInstanceByTypeForwarding),
|
||||
("testThatItCanResolveOptional", testThatItCanResolveOptional),
|
||||
("testThatItReusesInstancesResolvedForOptionalType", testThatItReusesInstancesResolvedForOptionalType),
|
||||
("testThatItFirstUsesTaggedDefinitionWhenResolvingOptional", testThatItFirstUsesTaggedDefinitionWhenResolvingOptional),
|
||||
("testThatItThrowsErrorWhenResolvingNotImplementedTypeWithTypeForwarding", testThatItThrowsErrorWhenResolvingNotImplementedTypeWithTypeForwarding),
|
||||
("testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType", testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType),
|
||||
@@ -154,9 +174,9 @@ class TypeForwardingTests: XCTestCase {
|
||||
var originalResolvingPropertiesCalled = false
|
||||
var resolvingPropertiesCalled = false
|
||||
container.register { ServiceImp1() }
|
||||
.resolvingProperties { _ in
|
||||
.resolvingProperties { _,_ in
|
||||
originalResolvingPropertiesCalled = true
|
||||
}.implements(Service.self) { _ in
|
||||
}.implements(Service.self) { _,_ in
|
||||
resolvingPropertiesCalled = true
|
||||
}
|
||||
|
||||
@@ -184,11 +204,11 @@ class TypeForwardingTests: XCTestCase {
|
||||
var resolvingPropertiesCalled = false
|
||||
container.reset()
|
||||
let definition = container.register { ServiceImp1() }
|
||||
.implements(Service.self) { container, object in
|
||||
.implements(Service.self) { _,_ in
|
||||
resolvingPropertiesCalled = true
|
||||
}
|
||||
|
||||
definition.resolvingProperties { _ in
|
||||
definition.resolvingProperties { _,_ in
|
||||
originalResolvingPropertiesCalled = true
|
||||
}
|
||||
|
||||
@@ -252,6 +272,35 @@ class TypeForwardingTests: XCTestCase {
|
||||
XCTAssertTrue(object is ServiceImp1)
|
||||
XCTAssertTrue(anyObject is ServiceImp1)
|
||||
}
|
||||
|
||||
func testThatItReusesInstancesResolvedForOptionalType() {
|
||||
var alreadyResolved = false
|
||||
container.register(.singleton) { () -> Dependency in
|
||||
XCTAssertFalse(alreadyResolved)
|
||||
return DependencyImpl() as Dependency
|
||||
}
|
||||
container.register() { DependencyClient(dependency: try! self.container.resolve()) }
|
||||
container.register() { OptionalDependencyClient(dependency: try! self.container.resolve()) }
|
||||
|
||||
let _ = try! container.resolve() as OptionalDependencyClient
|
||||
let _ = try! container.resolve() as DependencyClient
|
||||
|
||||
alreadyResolved = false
|
||||
|
||||
let _ = try! container.resolve() as DependencyClient
|
||||
let _ = try! container.resolve() as OptionalDependencyClient
|
||||
|
||||
container.register(.singleton) { () -> Dependency in
|
||||
XCTAssertFalse(alreadyResolved)
|
||||
return DependencyRefImpl() as Dependency
|
||||
}
|
||||
|
||||
let client1 = try! container.resolve() as DependencyClient
|
||||
let client2 = try! container.resolve() as OptionalDependencyClient
|
||||
|
||||
XCTAssertTrue(client1.dep as! DependencyRefImpl === client2.dep as! DependencyRefImpl)
|
||||
}
|
||||
|
||||
|
||||
func testThatItFirstUsesTaggedDefinitionWhenResolvingOptional() {
|
||||
let expectedTag: DependencyContainer.Tag = .String("tag")
|
||||
|
||||
Reference in New Issue
Block a user