Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3b2f5a272f | |||
| eab2d424e7 | |||
| 0f2cda0a52 | |||
| 05c02c9645 | |||
| fa086dad8f | |||
| cdc09f5a03 | |||
| b94ed3bea2 | |||
| 0fd70e65dd | |||
| 97e7f4782f | |||
| f1fdbbc988 | |||
| e368bb3051 | |||
| 4ce4832960 | |||
| d3bd0c27e3 | |||
| be0c39ab6b | |||
| 0de45e7d53 | |||
| 3b421d0cff | |||
| f1234bf2b9 | |||
| b0d7153bfe | |||
| 0193aa6bf6 | |||
| de7ad3ac48 | |||
| 40ad490c48 | |||
| 95cc5df26f | |||
| 09a7115aff | |||
| 15c0002ea3 | |||
| 0644d85a9c | |||
| e1522a0bf3 | |||
| a659415496 | |||
| efe25d575b | |||
| 22c67fa30c | |||
| 7a091da44d | |||
| 9580976dd8 | |||
| a4f0256313 | |||
| 815e9ccd66 | |||
| 530a20999a | |||
| 4f3bc1e498 | |||
| 8dcb136ff0 | |||
| 88d02af706 | |||
| a8777c067e | |||
| db40e8580c | |||
| 334fb384a5 | |||
| 54e1db2232 | |||
| c5c6bd2821 | |||
| 593129c63e | |||
| 9a8d919a13 | |||
| 17a2d64361 | |||
| 27037c2dd7 | |||
| bd253f4b0a | |||
| 882b2a2031 | |||
| 6a14c1f96d | |||
| f60e322445 | |||
| 77f6fde2fa | |||
| a8f7a2972a | |||
| ce9088afc7 | |||
| ef563c65ba | |||
| 90ff39c720 | |||
| e45dbd634f | |||
| f81c267c61 | |||
| 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 |
@@ -36,3 +36,4 @@ Carthage
|
||||
# SPM
|
||||
.build/
|
||||
Packages
|
||||
.swiftpm
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
3.1
|
||||
+22
-14
@@ -3,21 +3,29 @@ matrix:
|
||||
- os: linux
|
||||
include:
|
||||
- script:
|
||||
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.1' ONLY_ACTIVE_ARCH=NO | xcpretty -c
|
||||
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
|
||||
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk macosx -destination 'platform=macOS,arch=x86_64' ONLY_ACTIVE_ARCH=NO | xcpretty -c
|
||||
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV 1080p,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
|
||||
# disable running watchos until https://github.com/travis-ci/travis-ci/issues/7580 is fixed
|
||||
#- 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=10.1' ONLY_ACTIVE_ARCH=NO | xcpretty -c
|
||||
- pod spec lint --allow-warnings
|
||||
# - pod spec lint --allow-warnings
|
||||
- carthage build --no-skip-current
|
||||
- swift package clean && swift build && swift test
|
||||
os: osx
|
||||
osx_image: xcode8.3
|
||||
osx_image: xcode10.2
|
||||
language: objective-c
|
||||
before_install:
|
||||
- gem install cocoapods --version 1.1.0.rc.2 --no-document
|
||||
- gem install cocoapods --version 1.8.4 --no-document
|
||||
- script:
|
||||
- swift build --clean && swift build && swift test
|
||||
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11,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
|
||||
# - pod spec lint --allow-warnings
|
||||
- carthage build --no-skip-current
|
||||
- swift package clean && swift build && swift test
|
||||
os: osx
|
||||
osx_image: xcode11.2
|
||||
language: objective-c
|
||||
before_install:
|
||||
- gem install cocoapods --version 1.8.4 --no-document
|
||||
- script:
|
||||
- swift package clean && swift build && swift test
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
@@ -25,13 +33,13 @@ 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-5.1-RELEASE
|
||||
- wget https://swift.org/builds/swift-5.1-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 && swift test
|
||||
- swift package clean && swift build && swift test
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
@@ -39,8 +47,8 @@ matrix:
|
||||
before_install:
|
||||
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
|
||||
- cd ..
|
||||
- export SWIFT_VERSION=swift-3.1-RELEASE
|
||||
- wget https://swift.org/builds/swift-3.1-release/ubuntu1404/$SWIFT_VERSION/$SWIFT_VERSION-ubuntu14.04.tar.gz
|
||||
- export SWIFT_VERSION=swift-5.0-RELEASE
|
||||
- wget https://swift.org/builds/swift-5.0-release/ubuntu1404/$SWIFT_VERSION/$SWIFT_VERSION-ubuntu14.04.tar.gz
|
||||
- tar xzf $SWIFT_VERSION-ubuntu14.04.tar.gz
|
||||
- export PATH="${PWD}/${SWIFT_VERSION}-ubuntu14.04/usr/bin:${PATH}"
|
||||
- cd Dip
|
||||
|
||||
@@ -1,5 +1,40 @@
|
||||
# CHANGELOG
|
||||
|
||||
## Develop
|
||||
|
||||
## 7.1.0
|
||||
|
||||
* You can now use a shorthand syntax for resolving a single property using a key path, i.e. `resolvingProperty(\.value)`.
|
||||
* Swift 5.0 support ([#224](https://github.com/AliSoftware/Dip/pull/224)).
|
||||
* Fixed resolving nested types with the same local names ([#221](https://github.com/AliSoftware/Dip/pull/221)).
|
||||
* `@Injected` and `@IntectedWeak` property wrappers ([#225](https://github.com/AliSoftware/Dip/pull/225)).
|
||||
* Thread safety can be disabled on container level.
|
||||
|
||||
## 7.0.1
|
||||
|
||||
* Added a workaround for Swift 4.2 regression related to retaining weak properties ([#214](https://github.com/AliSoftware/Dip/issues/214)).
|
||||
For that auto-injection can be disabled or enabled for the whole container or individula registrations.
|
||||
|
||||
## 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.
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "Dip"
|
||||
s.version = "5.1"
|
||||
s.version = "7.1.0"
|
||||
s.summary = "Dependency Injection for Swift made easy."
|
||||
|
||||
s.description = <<-DESC
|
||||
@@ -23,4 +23,6 @@ Pod::Spec.new do |s|
|
||||
s.requires_arc = true
|
||||
|
||||
s.source_files = 'Sources/**/*.swift'
|
||||
|
||||
s.swift_version = "5.0", "5.1"
|
||||
end
|
||||
|
||||
@@ -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>
|
||||
@@ -31,6 +31,8 @@
|
||||
09FC480F1DAA9CAF00566AA8 /* Register.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC480C1DAA9CAF00566AA8 /* Register.swift */; };
|
||||
09FC48181DAAA53100566AA8 /* DipError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48161DAAA53100566AA8 /* DipError.swift */; };
|
||||
09FC481E1DAAA8F900566AA8 /* ComponentScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC481C1DAAA8F900566AA8 /* ComponentScope.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 */
|
||||
@@ -71,6 +73,11 @@
|
||||
09FC480C1DAA9CAF00566AA8 /* Register.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Register.swift; path = ../../Sources/Register.swift; sourceTree = "<group>"; };
|
||||
09FC48161DAAA53100566AA8 /* DipError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DipError.swift; path = ../../Sources/DipError.swift; sourceTree = "<group>"; };
|
||||
09FC481C1DAAA8F900566AA8 /* ComponentScope.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComponentScope.swift; path = ../../Sources/ComponentScope.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 */
|
||||
@@ -108,6 +115,7 @@
|
||||
095F829B1D043B41008CD706 /* TypeForwarding.swift */,
|
||||
0982AF0B1C5183A000B62463 /* Utils.swift */,
|
||||
09871B401DAA6BF300B40B91 /* Compatibility.swift */,
|
||||
63937A6921524C0B00AEE75A /* StoryboardInstantiatable.swift */,
|
||||
0919F4CB1C16417000DC3B10 /* Info.plist */,
|
||||
);
|
||||
path = Dip;
|
||||
@@ -125,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 */,
|
||||
);
|
||||
@@ -189,6 +201,7 @@
|
||||
buildPhases = (
|
||||
0903B35D1C161543002241C1 /* Sources */,
|
||||
0903B35E1C161543002241C1 /* Frameworks */,
|
||||
63937A7721524E3B00AEE75A /* ShellScript */,
|
||||
0903B35F1C161543002241C1 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
@@ -208,25 +221,26 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0730;
|
||||
LastUpgradeCheck = 0800;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = AliSoftware;
|
||||
TargetAttributes = {
|
||||
0903B3571C161543002241C1 = {
|
||||
CreatedOnToolsVersion = 7.1.1;
|
||||
LastSwiftMigration = 0800;
|
||||
LastSwiftMigration = 1020;
|
||||
};
|
||||
0903B3601C161543002241C1 = {
|
||||
CreatedOnToolsVersion = 7.1.1;
|
||||
LastSwiftMigration = 0800;
|
||||
LastSwiftMigration = 1020;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 0945268B1BEA1CFF0034E72A /* Build configuration list for PBXProject "Dip" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 094526871BEA1CFF0034E72A;
|
||||
productRefGroup = 094526921BEA1CFF0034E72A /* Products */;
|
||||
@@ -256,6 +270,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;
|
||||
@@ -265,6 +299,7 @@
|
||||
0982AF0C1C5183A000B62463 /* Utils.swift in Sources */,
|
||||
0919F4D51C16417B00DC3B10 /* Definition.swift in Sources */,
|
||||
09FC481E1DAAA8F900566AA8 /* ComponentScope.swift in Sources */,
|
||||
63937A6A21524C0B00AEE75A /* StoryboardInstantiatable.swift in Sources */,
|
||||
09B036001C5D2B83001EA5B7 /* AutoWiring.swift in Sources */,
|
||||
0919F4D41C16417B00DC3B10 /* Dip.swift in Sources */,
|
||||
09FC480F1DAA9CAF00566AA8 /* Register.swift in Sources */,
|
||||
@@ -282,6 +317,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 */,
|
||||
@@ -325,6 +361,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.Dip;
|
||||
PRODUCT_NAME = Dip;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -344,6 +381,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.Dip;
|
||||
PRODUCT_NAME = Dip;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -359,7 +397,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 = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -375,6 +419,8 @@
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STORYBOARD_NAME_PREFIX = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -382,24 +428,33 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
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.1;
|
||||
CURRENT_PROJECT_VERSION = 7.0.1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -424,12 +479,12 @@
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0.2;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,3,4";
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -437,24 +492,33 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
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.1;
|
||||
CURRENT_PROJECT_VERSION = 7.0.1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -472,13 +536,13 @@
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0.2;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,3,4";
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "1020"
|
||||
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.1.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.1.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.
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.0)
|
||||
activesupport (4.2.11)
|
||||
i18n (~> 0.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
atomos (0.1.3)
|
||||
claide (1.0.2)
|
||||
cocoapods (1.4.0)
|
||||
activesupport (>= 4.0.2, < 5)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
cocoapods-core (= 1.4.0)
|
||||
cocoapods-deintegrate (>= 1.0.2, < 2.0)
|
||||
cocoapods-downloader (>= 1.1.3, < 2.0)
|
||||
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||
cocoapods-search (>= 1.0.0, < 2.0)
|
||||
cocoapods-stats (>= 1.0.0, < 2.0)
|
||||
cocoapods-trunk (>= 1.3.0, < 2.0)
|
||||
cocoapods-try (>= 1.1.0, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
escape (~> 0.0.4)
|
||||
fourflusher (~> 2.0.1)
|
||||
gh_inspector (~> 1.0)
|
||||
molinillo (~> 0.6.4)
|
||||
nap (~> 1.0)
|
||||
ruby-macho (~> 1.1)
|
||||
xcodeproj (>= 1.5.4, < 2.0)
|
||||
cocoapods-core (1.4.0)
|
||||
activesupport (>= 4.0.2, < 6)
|
||||
fuzzy_match (~> 2.0.4)
|
||||
nap (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.2)
|
||||
cocoapods-downloader (1.2.2)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.0)
|
||||
cocoapods-stats (1.0.0)
|
||||
cocoapods-trunk (1.3.1)
|
||||
nap (>= 0.8, < 2.0)
|
||||
netrc (~> 0.11)
|
||||
cocoapods-try (1.1.0)
|
||||
colored2 (3.1.2)
|
||||
concurrent-ruby (1.1.4)
|
||||
escape (0.0.4)
|
||||
fourflusher (2.0.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.1.3)
|
||||
i18n (0.9.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
minitest (5.11.3)
|
||||
molinillo (0.6.6)
|
||||
nanaimo (0.2.6)
|
||||
nap (1.1.0)
|
||||
netrc (0.11.0)
|
||||
ruby-macho (1.3.1)
|
||||
thread_safe (0.3.6)
|
||||
tzinfo (1.2.5)
|
||||
thread_safe (~> 0.1)
|
||||
xcodeproj (1.7.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.2.6)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
cocoapods (= 1.4.0)
|
||||
|
||||
BUNDLED WITH
|
||||
1.16.5
|
||||
@@ -0,0 +1,8 @@
|
||||
import XCTest
|
||||
|
||||
import DipTests
|
||||
|
||||
var tests = [XCTestCaseEntry]()
|
||||
tests += DipTests.__allTests()
|
||||
|
||||
XCTMain(tests)
|
||||
+9
-24
@@ -1,30 +1,15 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// swift-tools-version:5.0
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "Dip"
|
||||
name: "Dip",
|
||||
products: [
|
||||
.library(name: "Dip", targets: ["Dip"]),
|
||||
],
|
||||
targets: [
|
||||
.target(name: "Dip", dependencies: [], path: "Sources"),
|
||||
.testTarget(name: "DipTests", dependencies: ["Dip"], path: "Tests"),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -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 = 1020;
|
||||
ORGANIZATIONNAME = AliSoftware;
|
||||
TargetAttributes = {
|
||||
0990225E1BC123C000E76F43 = {
|
||||
@@ -292,7 +292,7 @@
|
||||
};
|
||||
buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "DipSampleApp" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
@@ -423,17 +423,28 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
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 +472,7 @@
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -469,17 +480,28 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
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 +520,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 = "1020"
|
||||
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" : {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<string>7.1.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<string>7.1.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
+206
-82
@@ -78,7 +78,7 @@ extension DependencyContainer {
|
||||
```
|
||||
|
||||
*/
|
||||
public protocol AutoInjectedPropertyBox: class {
|
||||
public protocol AutoInjectedPropertyBox {
|
||||
///The type of wrapped property.
|
||||
static var wrappedType: Any.Type { get }
|
||||
|
||||
@@ -93,40 +93,108 @@ public protocol AutoInjectedPropertyBox: class {
|
||||
func resolve(_ container: DependencyContainer) throws
|
||||
}
|
||||
|
||||
#if swift(>=5.1)
|
||||
/**
|
||||
Use this wrapper to identify _strong_ properties of the instance that should be
|
||||
auto-injected by `DependencyContainer`. Type T can be any type.
|
||||
|
||||
- warning: Do not define this property as optional or container will not be able to inject it.
|
||||
Instead define it with initial value of `Injected<T>()`.
|
||||
|
||||
|
||||
**Example**:
|
||||
|
||||
```swift
|
||||
class ClientImp: Client {
|
||||
@Injected var service: Service?
|
||||
}
|
||||
```
|
||||
|
||||
- seealso: `InjectedWeak`
|
||||
|
||||
*/
|
||||
@propertyWrapper
|
||||
public struct Injected<T>: _InjectedPropertyBox, AutoInjectedPropertyBox {
|
||||
let valueBox: NullableBox<T> = NullableBox(nil)
|
||||
|
||||
///Wrapped value.
|
||||
public var wrappedValue: T? {
|
||||
get {
|
||||
return valueBox.unboxed
|
||||
}
|
||||
set {
|
||||
guard (required && newValue != nil) || !required else {
|
||||
fatalError("Can not set required property to nil.")
|
||||
}
|
||||
valueBox.unboxed = newValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let required: Bool
|
||||
let didInject: (T) -> ()
|
||||
let tag: DependencyContainer.Tag?
|
||||
let overrideTag: Bool
|
||||
|
||||
public init(wrappedValue initialValue: T?) {
|
||||
self.init()
|
||||
}
|
||||
}
|
||||
#else
|
||||
/**
|
||||
Use this wrapper to identify _strong_ properties of the instance that should be
|
||||
auto-injected by `DependencyContainer`. Type T can be any type.
|
||||
|
||||
- warning: Do not define this property as optional or container will not be able to inject it.
|
||||
Instead define it with initial value of `Injected<T>()`.
|
||||
|
||||
**Example**:
|
||||
|
||||
```swift
|
||||
class ClientImp: Client {
|
||||
var service = Injected<Service>()
|
||||
}
|
||||
```
|
||||
|
||||
- seealso: `InjectedWeak`
|
||||
|
||||
*/
|
||||
public final class Injected<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox {
|
||||
|
||||
*/
|
||||
public struct Injected<T>: _InjectedPropertyBox, AutoInjectedPropertyBox {
|
||||
let valueBox: NullableBox<T> = NullableBox(nil)
|
||||
|
||||
///Wrapped value.
|
||||
public var value: T? {
|
||||
return valueBox.unboxed
|
||||
}
|
||||
|
||||
let required: Bool
|
||||
let didInject: (T) -> ()
|
||||
let tag: DependencyContainer.Tag?
|
||||
let overrideTag: Bool
|
||||
|
||||
/// Returns a new wrapper with provided value.
|
||||
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)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public extension Injected {
|
||||
///The type of wrapped property.
|
||||
public static var wrappedType: Any.Type {
|
||||
static var wrappedType: Any.Type {
|
||||
return T.self
|
||||
}
|
||||
|
||||
///Wrapped value.
|
||||
public internal(set) var value: T? {
|
||||
didSet {
|
||||
if let value = value { didInject(value) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
self.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
self.valueBox.unboxed = value
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,30 +208,24 @@ public final class Injected<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox
|
||||
- didInject: Block that will be called when concrete instance is injected in this property.
|
||||
Similar to `didSet` property observer. Default value does nothing.
|
||||
*/
|
||||
public convenience init(required: Bool = true, didInject: @escaping (T) -> () = { _ in }) {
|
||||
init(required: Bool = true, didInject: @escaping (T) -> () = { _ in }) {
|
||||
self.init(value: nil, required: required, tag: nil, overrideTag: false, didInject: didInject)
|
||||
}
|
||||
|
||||
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: @escaping (T) -> () = { _ in }) {
|
||||
init(required: Bool = true, tag: DependencyTagConvertible?, didInject: @escaping (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.")
|
||||
func resolve(_ container: DependencyContainer) throws {
|
||||
let resolved: T? = try self.resolve(with: container, tag: tag, overrideTag: overrideTag, required: required)
|
||||
valueBox.unboxed = resolved
|
||||
if let resolved = resolved {
|
||||
didInject(resolved)
|
||||
}
|
||||
|
||||
return Injected(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if swift(>=5.1)
|
||||
/**
|
||||
Use this wrapper to identify _weak_ properties of the instance that should be
|
||||
auto-injected by `DependencyContainer`. Type T should be a **class** type.
|
||||
@@ -185,42 +247,124 @@ public final class Injected<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox
|
||||
|
||||
```swift
|
||||
class ServiceImp: Service {
|
||||
var client = InjectedWeak<Client>()
|
||||
@InjectedWeak var client: Client?
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- seealso: `Injected`
|
||||
|
||||
*/
|
||||
public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox {
|
||||
@propertyWrapper
|
||||
public struct InjectedWeak<T>: _InjectedPropertyBox, AutoInjectedPropertyBox {
|
||||
|
||||
//Only classes (means AnyObject) can be used as `weak` properties
|
||||
//but we can not make <T: AnyObject> because that will prevent using protocol as generic type
|
||||
//so we just rely on user reading documentation and passing AnyObject in runtime
|
||||
//also we will throw fatal error if type can not be casted to AnyObject during resolution.
|
||||
|
||||
///The type of wrapped property.
|
||||
public static var wrappedType: Any.Type {
|
||||
return T.self
|
||||
}
|
||||
|
||||
var valueBox: WeakBox<T>? = nil {
|
||||
didSet {
|
||||
if let value = value { didInject(value) }
|
||||
|
||||
let valueBox: WeakBox<T> = WeakBox(nil)
|
||||
|
||||
///Wrapped value.
|
||||
public var wrappedValue: T? {
|
||||
get {
|
||||
return valueBox.value
|
||||
}
|
||||
set {
|
||||
guard (required && newValue != nil) || !required else {
|
||||
fatalError("Can not set required property to nil.")
|
||||
}
|
||||
|
||||
valueBox.unboxed = newValue as AnyObject
|
||||
}
|
||||
}
|
||||
|
||||
let required: Bool
|
||||
let didInject: (T) -> ()
|
||||
let tag: DependencyContainer.Tag?
|
||||
let overrideTag: Bool
|
||||
|
||||
public init(wrappedValue initialValue: T?) {
|
||||
self.init()
|
||||
}
|
||||
}
|
||||
#else
|
||||
/**
|
||||
Use this wrapper to identify _weak_ properties of the instance that should be
|
||||
auto-injected by `DependencyContainer`. Type T should be a **class** type.
|
||||
Otherwise it will cause runtime exception when container will try to resolve the property.
|
||||
Use this wrapper to define one of two circular dependencies to avoid retain cycle.
|
||||
|
||||
- note: The only difference between `InjectedWeak` and `Injected` is that `InjectedWeak` uses
|
||||
_weak_ reference to store underlying value, when `Injected` uses _strong_ reference.
|
||||
For that reason if you resolve instance that has a _weak_ auto-injected property this property
|
||||
will be released when `resolve` will complete.
|
||||
|
||||
Use `InjectedWeak<T>` to define one of two circular dependecies if another dependency is defined as `Injected<U>`.
|
||||
This will prevent a retain cycle between resolved instances.
|
||||
|
||||
- warning: Do not define this property as optional or container will not be able to inject it.
|
||||
Instead define it with initial value of `InjectedWeak<T>()`.
|
||||
|
||||
**Example**:
|
||||
|
||||
```swift
|
||||
class ServiceImp: Service {
|
||||
var client = InjectedWeak<Client>()
|
||||
}
|
||||
```
|
||||
|
||||
- seealso: `Injected`
|
||||
|
||||
*/
|
||||
public struct InjectedWeak<T>: _InjectedPropertyBox, AutoInjectedPropertyBox {
|
||||
|
||||
//Only classes (means AnyObject) can be used as `weak` properties
|
||||
//but we can not make <T: AnyObject> because that will prevent using protocol as generic type
|
||||
//so we just rely on user reading documentation and passing AnyObject in runtime
|
||||
//also we will throw fatal error if type can not be casted to AnyObject during resolution.
|
||||
|
||||
let valueBox: WeakBox<T> = WeakBox(nil)
|
||||
|
||||
///Wrapped value.
|
||||
public var value: T? {
|
||||
return valueBox?.value
|
||||
return valueBox.value
|
||||
}
|
||||
|
||||
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)
|
||||
let required: Bool
|
||||
let didInject: (T) -> ()
|
||||
let tag: DependencyContainer.Tag?
|
||||
let overrideTag: Bool
|
||||
|
||||
|
||||
/// Returns a new wrapper with provided value.
|
||||
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
|
||||
|
||||
public extension InjectedWeak {
|
||||
///The type of wrapped property.
|
||||
static var wrappedType: Any.Type {
|
||||
return T.self
|
||||
}
|
||||
|
||||
init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> ()) {
|
||||
self.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
self.valueBox.unboxed = value as AnyObject
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new wrapper for weak auto-injected property.
|
||||
|
||||
@@ -232,50 +376,32 @@ public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropert
|
||||
- didInject: Block that will be called when concrete instance is injected in this property.
|
||||
Similar to `didSet` property observer. Default value does nothing.
|
||||
*/
|
||||
public convenience init(required: Bool = true, didInject: @escaping (T) -> () = { _ in }) {
|
||||
init(required: Bool = true, didInject: @escaping (T) -> () = { _ in }) {
|
||||
self.init(value: nil, required: required, tag: nil, overrideTag: false, didInject: didInject)
|
||||
}
|
||||
|
||||
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: @escaping (T) -> () = { _ in }) {
|
||||
init(required: Bool = true, tag: DependencyTagConvertible?, didInject: @escaping (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.")
|
||||
func resolve(_ container: DependencyContainer) throws {
|
||||
let resolved: T? = try self.resolve(with: container, tag: tag, overrideTag: overrideTag, required: required)
|
||||
valueBox.unboxed = resolved as AnyObject
|
||||
if let resolved = resolved {
|
||||
didInject(resolved)
|
||||
}
|
||||
|
||||
return InjectedWeak(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class _InjectedPropertyBox<T> {
|
||||
protocol _InjectedPropertyBox {}
|
||||
|
||||
let required: Bool
|
||||
let didInject: (T) -> ()
|
||||
let tag: DependencyContainer.Tag?
|
||||
let overrideTag: Bool
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func resolve(with container: DependencyContainer) throws -> T? {
|
||||
let tag = overrideTag ? self.tag : container.context.tag
|
||||
extension _InjectedPropertyBox {
|
||||
func resolve<T>(with container: DependencyContainer, tag: DependencyContainer.Tag?, overrideTag: Bool, required: Bool) throws -> T? {
|
||||
let tag = overrideTag ? 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)
|
||||
@@ -289,12 +415,10 @@ class _InjectedPropertyBox<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private func resolve<U>(with container: DependencyContainer, key: DefinitionKey, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
|
||||
func resolve<U>(with container: DependencyContainer, key: DefinitionKey, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
|
||||
return try container._resolve(key: key, builder: { definition throws -> Any in
|
||||
try builder(definition.weakFactory)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
#if _runtime(_ObjC)
|
||||
extension String {
|
||||
func has(prefix aPrefix: String) -> Bool {
|
||||
return hasPrefix(aPrefix)
|
||||
}
|
||||
extension String {
|
||||
func has(prefix aPrefix: String) -> Bool {
|
||||
return hasPrefix(aPrefix)
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
extension String {
|
||||
func has(prefix aPrefix: String) -> Bool {
|
||||
return aPrefix ==
|
||||
String(self.characters.prefix(aPrefix.characters.count))
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -35,10 +35,10 @@ public enum ComponentScope {
|
||||
```
|
||||
container.register { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
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
|
||||
@@ -59,10 +59,10 @@ public enum ComponentScope {
|
||||
```
|
||||
container.register { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
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
|
||||
@@ -89,10 +89,10 @@ public enum ComponentScope {
|
||||
```
|
||||
container.register(.singleton) { ServiceImp() as Service }
|
||||
container.register {
|
||||
ServiceConsumerImp(
|
||||
service1: try container.resolve() as Service
|
||||
service2: try container.resolve() as Service
|
||||
) as ServiceConsumer
|
||||
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
|
||||
|
||||
+47
-15
@@ -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?
|
||||
@@ -34,12 +34,14 @@ public struct DefinitionKey : Hashable, CustomStringConvertible {
|
||||
self.tag = tag
|
||||
}
|
||||
|
||||
public var hashValue: Int {
|
||||
return "\(type)-\(typeOfArguments)-\(tag.desc)".hashValue
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(ObjectIdentifier(type))
|
||||
hasher.combine(ObjectIdentifier(typeOfArguments))
|
||||
hasher.combine(tag.desc)
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
return "type: \(type), arguments: \(typeOfArguments), tag: \(tag.desc)"
|
||||
return "type: \(String(reflecting: type)), arguments: \(typeOfArguments), tag: \(tag.desc)"
|
||||
}
|
||||
|
||||
func tagged(with tag: DependencyContainer.Tag?) -> DefinitionKey {
|
||||
@@ -47,15 +49,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
|
||||
lhs.tag.desc == rhs.tag.desc
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///Dummy protocol to store definitions for different types in collection
|
||||
@@ -80,6 +82,7 @@ public final class Definition<T, U>: DefinitionType {
|
||||
let scope: ComponentScope
|
||||
var weakFactory: ((Any) throws -> Any)!
|
||||
var resolveProperties: ((DependencyContainer, Any) throws -> ())?
|
||||
var autoInjectProperties: Bool?
|
||||
|
||||
init(scope: ComponentScope, factory: @escaping F) {
|
||||
self.factory = factory
|
||||
@@ -125,6 +128,34 @@ public final class Definition<T, U>: DefinitionType {
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult public func resolvingProperty<Root, V>(_ keyPath: ReferenceWritableKeyPath<Root, V>, as type: Any.Type = V.self, tag: DependencyTagConvertible? = nil) -> Definition {
|
||||
return resolvingProperties { (container, instance) in
|
||||
precondition(instance is Root, "Type of resolved instance \(Swift.type(of: instance)) does not match expected type \(Root.self)")
|
||||
let resolved = try container.resolve(type, tag: tag)
|
||||
precondition(resolved is V, "Type of resolved property \(Swift.type(of: resolved)) does not match expected type \(type)")
|
||||
(instance as! Root)[keyPath: keyPath] = resolved as! V
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult public func resolvingProperty<Root, V>(_ keyPath: ReferenceWritableKeyPath<Root, V>, factory: @escaping (DependencyContainer) throws -> V = { try $0.resolve() }) -> Definition {
|
||||
return resolvingProperties { (container, instance) in
|
||||
precondition(instance is Root, "Type of resolved instance \(Swift.type(of: instance)) does not match expected type \(Root.self)")
|
||||
(instance as! Root)[keyPath: keyPath] = try factory(container)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Whether container should perform properties auto-injection when resolving using this definition.
|
||||
If called will override container configuration. Can be called together with `resolvingProperties`
|
||||
to resolve properties that are not automatically injected.
|
||||
|
||||
- parameter shouldAutoInject: Whether container should perform properties auto-injection when resolving using this definition. Default is `true`.
|
||||
*/
|
||||
@discardableResult public func autoInjectingProperties(_ shouldAutoInject: Bool = true) -> Definition {
|
||||
autoInjectProperties = shouldAutoInject
|
||||
return self
|
||||
}
|
||||
|
||||
/// Calls `resolveDependencies` block if it was set.
|
||||
func resolveProperties(of instance: Any, container: DependencyContainer) throws {
|
||||
guard let resolvedInstance = instance as? T else { return }
|
||||
@@ -144,7 +175,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 {
|
||||
@@ -198,18 +229,19 @@ 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 }
|
||||
func resolveProperties(of instance: Any, container: DependencyContainer) throws
|
||||
var container: DependencyContainer? { get set }
|
||||
var autoInjectProperties: Bool? { get }
|
||||
}
|
||||
|
||||
//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])
|
||||
|
||||
+63
-24
@@ -34,11 +34,13 @@ public final class DependencyContainer {
|
||||
|
||||
- seealso: `DependencyTagConvertible`
|
||||
*/
|
||||
public enum Tag: Equatable {
|
||||
public enum Tag {
|
||||
case String(StringLiteralType)
|
||||
case Int(IntegerLiteralType)
|
||||
}
|
||||
|
||||
|
||||
var autoInjectProperties: Bool
|
||||
var threadSafe: Bool
|
||||
internal(set) public var context: Context!
|
||||
var definitions = [DefinitionKey: _Definition]()
|
||||
var resolvedInstances = ResolvedInstances()
|
||||
@@ -50,7 +52,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)
|
||||
@@ -59,8 +61,11 @@ public final class DependencyContainer {
|
||||
|
||||
/**
|
||||
Designated initializer for a DependencyContainer
|
||||
|
||||
- parameter configBlock: A configuration block in which you typically put all you `register` calls.
|
||||
|
||||
- Parameters:
|
||||
- autoInjectProperties: Whether container should perform properties auto-injection. Default is `true`.
|
||||
- threadSafe: Whether container should be thread-safe. Default is `true`. You may want to disable it for better performance.
|
||||
- configBlock: A configuration block in which you typically put all you `register` calls.
|
||||
|
||||
- note: The `configBlock` is simply called at the end of the `init` to let you configure everything.
|
||||
It is only present for convenience to have a cleaner syntax when declaring and initializing
|
||||
@@ -79,7 +84,9 @@ public final class DependencyContainer {
|
||||
|
||||
- returns: A new DependencyContainer.
|
||||
*/
|
||||
public init(configBlock: (DependencyContainer)->() = { _ in }) {
|
||||
public init(autoInjectProperties: Bool = true, threadSafe: Bool = true, configBlock: (DependencyContainer)->() = { _ in }) {
|
||||
self.autoInjectProperties = autoInjectProperties
|
||||
self.threadSafe = threadSafe
|
||||
configBlock(self)
|
||||
}
|
||||
|
||||
@@ -100,6 +107,10 @@ public final class DependencyContainer {
|
||||
}
|
||||
|
||||
func threadSafe<T>(_ closure: () throws -> T) rethrows -> T {
|
||||
guard threadSafe else {
|
||||
return try closure()
|
||||
}
|
||||
|
||||
lock.lock()
|
||||
defer { lock.unlock() }
|
||||
return try closure()
|
||||
@@ -167,12 +178,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 {
|
||||
@@ -196,7 +210,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
|
||||
@@ -207,6 +221,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)
|
||||
@@ -222,7 +240,8 @@ extension DependencyContainer {
|
||||
context = Context(
|
||||
key: key,
|
||||
injectedInType: injectedInType,
|
||||
injectedInProperty: injectedInProperty
|
||||
injectedInProperty: injectedInProperty,
|
||||
inCollaboration: inCollaboration
|
||||
)
|
||||
context.logErrors = logErrors ?? currentContext?.logErrors ?? true
|
||||
|
||||
@@ -258,17 +277,17 @@ extension DependencyContainer {
|
||||
_collaborators += containers
|
||||
for container in containers {
|
||||
container._collaborators += [self]
|
||||
container.resolvedInstances.singletonsBox = self.resolvedInstances.singletonsBox
|
||||
container.resolvedInstances.weakSingletonsBox = self.resolvedInstances.weakSingletonsBox
|
||||
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.singletonsBox !== collaborator.resolvedInstances.singletonsBox else { continue }
|
||||
container.resolvedInstances.singletonsBox = collaborator.resolvedInstances.singletonsBox
|
||||
container.resolvedInstances.weakSingletonsBox = collaborator.resolvedInstances.weakSingletonsBox
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -291,11 +310,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)
|
||||
}
|
||||
|
||||
@@ -336,6 +367,8 @@ extension DependencyContainer {
|
||||
definitions[key] = nil
|
||||
resolvedInstances.singletons[key] = nil
|
||||
resolvedInstances.weakSingletons[key] = nil
|
||||
resolvedInstances.sharedSingletons[key] = nil
|
||||
resolvedInstances.sharedWeakSingletons[key] = nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,6 +381,8 @@ extension DependencyContainer {
|
||||
definitions.removeAll()
|
||||
resolvedInstances.singletons.removeAll()
|
||||
resolvedInstances.weakSingletons.removeAll()
|
||||
resolvedInstances.sharedSingletons.removeAll()
|
||||
resolvedInstances.sharedWeakSingletons.removeAll()
|
||||
bootstrapped = false
|
||||
}
|
||||
}
|
||||
@@ -477,13 +512,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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -77,18 +77,16 @@ public enum DipError: Error, CustomStringConvertible {
|
||||
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)."
|
||||
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 \(String(reflecting: key.type))."
|
||||
case let .autoInjectionFailed(label, type, error):
|
||||
return "Failed to auto-inject property \"\(label.desc)\" of type \(type). \(error)"
|
||||
return "Failed to auto-inject property \"\(label.desc)\" of type \(String(reflecting: type)). \(error)"
|
||||
case let .autoWiringFailed(type, error):
|
||||
return "Failed to auto-wire type \"\(type)\". \(error)"
|
||||
return "Failed to auto-wire type \"\(String(reflecting: type))\". \(error)"
|
||||
case let .ambiguousDefinitions(type, definitions):
|
||||
return "Ambiguous definitions for \(type):\n" +
|
||||
return "Ambiguous definitions for \(String(reflecting: 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)."
|
||||
return "Resolved instance \(resolved ?? "nil") does not implement expected type \(String(reflecting: key.type))."
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -71,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 })
|
||||
|
||||
+84
-37
@@ -46,7 +46,7 @@ extension DependencyContainer {
|
||||
- seealso: `register(_:type:tag:factory:)`
|
||||
*/
|
||||
public func resolve<T>(tag: DependencyTagConvertible? = nil) throws -> T {
|
||||
return try resolve(tag: tag) { factory in try factory() }
|
||||
return try _resolve(tag: tag) { (factory: () throws -> T) in try factory() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +73,7 @@ extension DependencyContainer {
|
||||
- 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() }
|
||||
return try resolve(type, tag: tag) { (factory: () throws -> Any) in try factory() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +103,11 @@ extension DependencyContainer {
|
||||
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:)`
|
||||
|
||||
@@ -113,13 +117,37 @@ extension DependencyContainer {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -136,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
|
||||
@@ -147,7 +183,7 @@ extension DependencyContainer {
|
||||
return previouslyResolved
|
||||
}
|
||||
|
||||
log(level: .Verbose, context)
|
||||
if let context = context { log(level: .Verbose, context) }
|
||||
var resolvedInstance = try builder(definition)
|
||||
|
||||
/*
|
||||
@@ -163,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
|
||||
}
|
||||
|
||||
@@ -175,14 +211,17 @@ 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)
|
||||
resolvable.resolveDependencies(self)
|
||||
}
|
||||
|
||||
try autoInjectProperties(in: resolvedInstance)
|
||||
|
||||
let shouldAutoInject = definition.autoInjectProperties ?? self.autoInjectProperties
|
||||
if shouldAutoInject {
|
||||
try autoInjectProperties(in: resolvedInstance)
|
||||
}
|
||||
try definition.resolveProperties(of: resolvedInstance, container: self)
|
||||
|
||||
log(level: .Verbose, "Resolved type \(key.type) with \(resolvedInstance)")
|
||||
@@ -191,7 +230,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
|
||||
@@ -199,7 +238,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
|
||||
}
|
||||
}
|
||||
@@ -207,7 +246,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)
|
||||
}
|
||||
@@ -230,41 +269,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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ extension DependencyContainer {
|
||||
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, ()> {
|
||||
@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
|
||||
@@ -127,7 +127,7 @@ extension DependencyContainer {
|
||||
|
||||
- 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> {
|
||||
@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)) }
|
||||
}
|
||||
|
||||
@@ -167,13 +167,14 @@ extension DependencyContainer {
|
||||
// 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)) }
|
||||
@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) }
|
||||
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2)) } as! T
|
||||
}
|
||||
|
||||
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
|
||||
@@ -184,13 +185,13 @@ extension DependencyContainer {
|
||||
// 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)) }
|
||||
@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) }
|
||||
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3)) } as! T
|
||||
}
|
||||
|
||||
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
|
||||
@@ -201,13 +202,13 @@ extension DependencyContainer {
|
||||
// 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)) }
|
||||
@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) }
|
||||
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4)) } as! T
|
||||
}
|
||||
|
||||
/// - seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
|
||||
@@ -218,13 +219,13 @@ extension DependencyContainer {
|
||||
// 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)) }
|
||||
@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) }
|
||||
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5)) } as! T
|
||||
}
|
||||
|
||||
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
|
||||
@@ -235,13 +236,13 @@ extension DependencyContainer {
|
||||
// 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)) }
|
||||
@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) }
|
||||
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:)`
|
||||
|
||||
@@ -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
|
||||
@@ -81,12 +81,6 @@ extension Definition {
|
||||
return implements(a).implements(b).implements(c)
|
||||
}
|
||||
|
||||
///Registers definition for types passed as parameters
|
||||
@available(*, deprecated: 5.1.0)
|
||||
@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)
|
||||
}
|
||||
|
||||
///Registers definition for types passed as parameters
|
||||
@discardableResult public func implements<A, B, C, D>(_ a: A.Type, _ b: B.Type, _ c: C.Type, _ d: D.Type) -> Definition {
|
||||
return implements(a).implements(b).implements(c).implements(d)
|
||||
|
||||
+9
-14
@@ -48,11 +48,6 @@ extension Optional: BoxType {
|
||||
}
|
||||
}
|
||||
|
||||
extension ImplicitlyUnwrappedOptional: BoxType {
|
||||
var unboxed: Any? {
|
||||
return self ?? nil
|
||||
}
|
||||
}
|
||||
|
||||
class Box<T> {
|
||||
var unboxed: T
|
||||
@@ -61,6 +56,13 @@ class Box<T> {
|
||||
}
|
||||
}
|
||||
|
||||
class NullableBox<T> {
|
||||
var unboxed: T?
|
||||
init(_ value: T?) {
|
||||
self.unboxed = value
|
||||
}
|
||||
}
|
||||
|
||||
protocol WeakBoxType {
|
||||
var unboxed: AnyObject? { get }
|
||||
}
|
||||
@@ -71,15 +73,8 @@ class WeakBox<T>: WeakBoxType {
|
||||
return unboxed as? T
|
||||
}
|
||||
|
||||
init(_ value: T) {
|
||||
#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))")
|
||||
}
|
||||
init(_ value: T?) {
|
||||
weak var value: AnyObject? = value as AnyObject
|
||||
self.unboxed = value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,34 @@ private protocol Client: class {
|
||||
var anotherServer: Server! {get set}
|
||||
}
|
||||
|
||||
#if swift(>=5.1)
|
||||
private class ServerImp: Server {
|
||||
|
||||
@InjectedWeak(didInject: { _ in
|
||||
AutoInjectionTests.clientDidInjectCalled = true
|
||||
}) var client: Client!
|
||||
|
||||
@InjectedWeak(required: false) var _optionalProperty: AnyObject?
|
||||
|
||||
weak var anotherClient: Client!
|
||||
}
|
||||
|
||||
private class ClientImp: Client {
|
||||
|
||||
@Injected(didInject: { _ in
|
||||
AutoInjectionTests.serverDidInjectCalled = true
|
||||
}) var server: Server
|
||||
|
||||
@Injected(required: false) var _optionalProperty: AnyObject?
|
||||
|
||||
@Injected(tag: "tagged") var taggedServer: Server
|
||||
@Injected(tag: nil) var nilTaggedServer: Server
|
||||
|
||||
var anotherServer: Server!
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
private class ServerImp: Server {
|
||||
|
||||
var _client = InjectedWeak<Client>() { _ in
|
||||
@@ -47,7 +75,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 {
|
||||
@@ -67,7 +95,18 @@ private class ClientImp: Client {
|
||||
var taggedServer = Injected<Server>(tag: "tagged")
|
||||
var nilTaggedServer = Injected<Server>(tag: nil)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if swift(>=5.1)
|
||||
private class Obj1 {
|
||||
@InjectedWeak var obj2: Obj2?
|
||||
@Injected var obj3: Obj3?
|
||||
}
|
||||
|
||||
private class Obj2 {
|
||||
@Injected var obj1: Obj1?
|
||||
}
|
||||
#else
|
||||
private class Obj1 {
|
||||
let obj2 = InjectedWeak<Obj2>()
|
||||
let obj3 = Injected<Obj3>()
|
||||
@@ -76,6 +115,7 @@ private class Obj1 {
|
||||
private class Obj2 {
|
||||
let obj1 = Injected<Obj1>()
|
||||
}
|
||||
#endif
|
||||
|
||||
private class Obj3 {
|
||||
|
||||
@@ -92,26 +132,6 @@ class AutoInjectionTests: XCTestCase {
|
||||
static var clientDidInjectCalled: Bool = false
|
||||
|
||||
let container = DependencyContainer()
|
||||
|
||||
static var allTests = {
|
||||
return [
|
||||
("testThatItResolvesAutoInjectedDependencies", testThatItResolvesAutoInjectedDependencies),
|
||||
("testThatItResolvesInheritedDependencies", testThatItResolvesInheritedDependencies),
|
||||
("testThatItCanSetInjectedProperty", testThatItCanSetInjectedProperty),
|
||||
("testThatItThrowsErrorIfFailsToAutoInjectDependency", testThatItThrowsErrorIfFailsToAutoInjectDependency),
|
||||
("testThatItResolvesAutoInjectedSingletons", testThatItResolvesAutoInjectedSingletons),
|
||||
("testThatItCallsResolveDependencyBlockWhenAutoInjecting", testThatItCallsResolveDependencyBlockWhenAutoInjecting),
|
||||
("testThatItReusesResolvedAutoInjectedInstances", testThatItReusesResolvedAutoInjectedInstances),
|
||||
("testThatItReusesAutoInjectedInstancesOnNextResolveOrAutoInjection", testThatItReusesAutoInjectedInstancesOnNextResolveOrAutoInjection),
|
||||
("testThatThereIsNoRetainCycleBetweenAutoInjectedCircularDependencies", testThatThereIsNoRetainCycleBetweenAutoInjectedCircularDependencies),
|
||||
("testThatItCallsDidInjectOnAutoInjectedProperty", testThatItCallsDidInjectOnAutoInjectedProperty),
|
||||
("testThatNoErrorThrownWhenOptionalPropertiesAreNotAutoInjected", testThatNoErrorThrownWhenOptionalPropertiesAreNotAutoInjected),
|
||||
("testThatItResolvesTaggedAutoInjectedProperties", testThatItResolvesTaggedAutoInjectedProperties),
|
||||
("testThatItPassesTagToAutoInjectedProperty", testThatItPassesTagToAutoInjectedProperty),
|
||||
("testThatItDoesNotPassTagToAutoInjectedPropertyWithExplicitTag", testThatItDoesNotPassTagToAutoInjectedPropertyWithExplicitTag),
|
||||
("testThatItAutoInjectsPropertyWithCollaboratingContainer", testThatItAutoInjectsPropertyWithCollaboratingContainer)
|
||||
]
|
||||
}()
|
||||
|
||||
override func setUp() {
|
||||
container.reset()
|
||||
@@ -128,10 +148,18 @@ class AutoInjectionTests: XCTestCase {
|
||||
|
||||
func testThatItResolvesInheritedDependencies() {
|
||||
class ServerImp2: ServerImp {
|
||||
#if swift(>=5.1)
|
||||
@InjectedWeak(didInject: { _ in
|
||||
XCTAssertTrue(AutoInjectionTests.serverDidInjectCalled, "Inherited properties should be resolved first")
|
||||
}) var client2: Client?
|
||||
#else
|
||||
var _client2 = InjectedWeak<Client>() { _ in
|
||||
XCTAssertTrue(AutoInjectionTests.serverDidInjectCalled, "Inherited properties should be resolved first")
|
||||
}
|
||||
var client2: Client? { return _client2.value }
|
||||
var client2: Client? {
|
||||
return _client2.value
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
container.register { ServerImp2() as Server }
|
||||
@@ -153,17 +181,23 @@ class AutoInjectionTests: XCTestCase {
|
||||
|
||||
let newServer = ServerImp()
|
||||
let newClient = ClientImp()
|
||||
#if swift(>=5.1)
|
||||
client.server = newServer
|
||||
server.client = newClient
|
||||
#else
|
||||
client._server = client._server.setValue(newServer)
|
||||
server._client = server._client.setValue(newClient)
|
||||
#endif
|
||||
|
||||
XCTAssertTrue(client.server === newServer)
|
||||
XCTAssertTrue(server.client === newClient)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func testThatItThrowsErrorIfFailsToAutoInjectDependency() {
|
||||
container.register { ClientImp() as Client }
|
||||
|
||||
AssertThrows(expression: try container.resolve() as Client)
|
||||
XCTAssertThrowsError(try self.container.resolve() as Client)
|
||||
}
|
||||
|
||||
func testThatItResolvesAutoInjectedSingletons() {
|
||||
@@ -245,11 +279,19 @@ class AutoInjectionTests: XCTestCase {
|
||||
let obj2 = try! container.resolve() as Obj2
|
||||
|
||||
//then
|
||||
XCTAssertTrue(obj2 === obj2.obj1.value!.obj2.value!,
|
||||
#if swift(>=5.1)
|
||||
XCTAssertTrue(obj2 === obj2.obj1!.obj2!,
|
||||
"Auto-injected instance should be reused on next auto-injection")
|
||||
|
||||
XCTAssertTrue(obj2.obj1.value! === obj2.obj1.value!.obj3.value!.obj1,
|
||||
XCTAssertTrue(obj2.obj1! === obj2.obj1!.obj3!.obj1,
|
||||
"Auto-injected instance should be reused on next resolve")
|
||||
#else
|
||||
XCTAssertTrue(obj2 === obj2.obj1.value!.obj2.value!,
|
||||
"Auto-injected instance should be reused on next auto-injection")
|
||||
|
||||
XCTAssertTrue(obj2.obj1.value! === obj2.obj1.value!.obj3.value!.obj1,
|
||||
"Auto-injected instance should be reused on next resolve")
|
||||
#endif
|
||||
}
|
||||
|
||||
func testThatThereIsNoRetainCycleBetweenAutoInjectedCircularDependencies() {
|
||||
@@ -294,7 +336,10 @@ class AutoInjectionTests: XCTestCase {
|
||||
container.register { ServerImp() as Server }
|
||||
container.register { ClientImp() as Client }
|
||||
|
||||
AssertNoThrow(expression: try container.resolve() as Client, "Container should not throw error if failed to resolve optional auto-injected properties.")
|
||||
XCTAssertNoThrow(
|
||||
try container.resolve() as Client,
|
||||
"Container should not throw error if failed to resolve optional auto-injected properties."
|
||||
)
|
||||
}
|
||||
|
||||
func testThatItResolvesTaggedAutoInjectedProperties() {
|
||||
@@ -307,7 +352,11 @@ class AutoInjectionTests: XCTestCase {
|
||||
let client = try! container.resolve() as Client
|
||||
|
||||
//then
|
||||
#if swift(>=5.1)
|
||||
let taggedServer = (client as! ClientImp).taggedServer!
|
||||
#else
|
||||
let taggedServer = (client as! ClientImp).taggedServer.value!
|
||||
#endif
|
||||
let server = client.server!
|
||||
|
||||
//server and tagged server should be resolved as different instances
|
||||
@@ -326,7 +375,11 @@ class AutoInjectionTests: XCTestCase {
|
||||
let client = try! container.resolve(tag: "tagged") as Client
|
||||
|
||||
//then
|
||||
#if swift(>=5.1)
|
||||
let taggedServer = (client as! ClientImp).taggedServer!
|
||||
#else
|
||||
let taggedServer = (client as! ClientImp).taggedServer.value!
|
||||
#endif
|
||||
let server = client.server!
|
||||
|
||||
//server and tagged server should be resolved as the same instance
|
||||
@@ -347,8 +400,13 @@ class AutoInjectionTests: XCTestCase {
|
||||
let client = try! container.resolve(tag: "otherTag") as Client
|
||||
|
||||
//then
|
||||
#if swift(>=5.1)
|
||||
let taggedServer = (client as! ClientImp).taggedServer!
|
||||
let nilTaggedServer = (client as! ClientImp).nilTaggedServer!
|
||||
#else
|
||||
let taggedServer = (client as! ClientImp).taggedServer.value!
|
||||
let nilTaggedServer = (client as! ClientImp).nilTaggedServer.value!
|
||||
#endif
|
||||
let server = client.server!
|
||||
|
||||
//server and tagged server should be resolved as different instances
|
||||
@@ -359,19 +417,89 @@ class AutoInjectionTests: XCTestCase {
|
||||
XCTAssertNotNil(taggedServer)
|
||||
XCTAssertNotNil(nilTaggedServer)
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Foo
|
||||
{
|
||||
struct Bar
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct Baz
|
||||
{
|
||||
struct Bar
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testScopedTypes() {
|
||||
let key1 = DefinitionKey(type: Baz.Bar.self, typeOfArguments: Void.self)
|
||||
let key2 = DefinitionKey(type: Foo.Bar.self, typeOfArguments: Void.self)
|
||||
|
||||
XCTAssertNotEqual(key1, key2)
|
||||
XCTAssertNotEqual(key1.hashValue, key2.hashValue)
|
||||
|
||||
container.register { Baz.Bar() }
|
||||
|
||||
XCTAssertNotNil(try? container.resolve() as Baz.Bar)
|
||||
XCTAssertThrowsError(try container.resolve() as Foo.Bar)
|
||||
|
||||
container.register { Foo.Bar() }
|
||||
|
||||
XCTAssertNotNil(try? container.resolve() as Foo.Bar)
|
||||
}
|
||||
|
||||
func testThatItAutoInjectsPropertyWithCollaboratingContainer() {
|
||||
let collaborator = DependencyContainer()
|
||||
collaborator.register { ServerImp() as Server }
|
||||
container.register { ClientImp() as Client }
|
||||
|
||||
|
||||
container.collaborate(with: collaborator)
|
||||
collaborator.collaborate(with: container)
|
||||
|
||||
|
||||
let client = try! container.resolve() as Client
|
||||
let server = client.server
|
||||
XCTAssertTrue(client === server?.client)
|
||||
}
|
||||
|
||||
|
||||
func testThatItDoesNotAutoInjectIfDisabledInDefinition() {
|
||||
container.register { ServerImp() as Server }
|
||||
container.register { ClientImp() as Client }
|
||||
.autoInjectingProperties(false)
|
||||
|
||||
let client = try! container.resolve() as Client
|
||||
let server = client.server
|
||||
|
||||
XCTAssertNil(server)
|
||||
}
|
||||
|
||||
func testThatItDoesNotAutoInjectIfDisabledInContainer() {
|
||||
let container = DependencyContainer(autoInjectProperties: false)
|
||||
container.register { ServerImp() as Server }
|
||||
container.register { ClientImp() as Client }
|
||||
|
||||
let client = try! container.resolve() as Client
|
||||
let server = client.server
|
||||
|
||||
XCTAssertNil(server)
|
||||
}
|
||||
|
||||
func testThatItAutoInjectsWhenOverridenInDefinition() {
|
||||
let container = DependencyContainer(autoInjectProperties: false)
|
||||
container.register { ServerImp() as Server }
|
||||
container.register { ClientImp() as Client }
|
||||
.autoInjectingProperties(true)
|
||||
|
||||
let client = try! container.resolve() as Client
|
||||
let server = client.server
|
||||
|
||||
XCTAssertNotNil(server)
|
||||
XCTAssertNil(server?.client)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -50,30 +50,6 @@ class AutoWiringTests: XCTestCase {
|
||||
|
||||
let container = DependencyContainer()
|
||||
|
||||
static var allTests = {
|
||||
return [
|
||||
("testThatItCanResolveWithAutoWiring", testThatItCanResolveWithAutoWiring),
|
||||
("testThatItUsesAutoWireFactoryWithMostNumberOfArguments", testThatItUsesAutoWireFactoryWithMostNumberOfArguments),
|
||||
("testThatItThrowsAmbiguityErrorWhenUsingAutoWire", testThatItThrowsAmbiguityErrorWhenUsingAutoWire),
|
||||
("testThatItUsesAutoWireFactoryWithMostNumberOfArguments", testThatItUsesAutoWireFactoryWithMostNumberOfArguments),
|
||||
("testThatItPrefersTaggedFactoryWithDifferentNumberOfArgumentsWhenUsingAutoWire", testThatItPrefersTaggedFactoryWithDifferentNumberOfArgumentsWhenUsingAutoWire),
|
||||
("testThatItPrefersTaggedFactoryWithDifferentTypesOfArgumentsWhenUsingAutoWire", testThatItPrefersTaggedFactoryWithDifferentTypesOfArgumentsWhenUsingAutoWire),
|
||||
("testThatItFallbackToNotTaggedFactoryWhenUsingAutoWire", testThatItFallbackToNotTaggedFactoryWhenUsingAutoWire),
|
||||
("testThatItDoesNotTryToUseAutoWiringWhenCallingResolveWithArguments", testThatItDoesNotTryToUseAutoWiringWhenCallingResolveWithArguments),
|
||||
("testThatItDoesNotUseAutoWiringWhenFailedToResolveLowLevelDependency", testThatItDoesNotUseAutoWiringWhenFailedToResolveLowLevelDependency),
|
||||
("testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgain", testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgain),
|
||||
("testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithTheSameTag", testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithTheSameTag),
|
||||
("testThatItDoesNotReuseInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithAnotherTag", testThatItDoesNotReuseInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithAnotherTag),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith1Argument", testThatItUsesTagToResolveDependenciesWithAutoWiringWith1Argument),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith2Arguments", testThatItUsesTagToResolveDependenciesWithAutoWiringWith2Arguments),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith3Arguments", testThatItUsesTagToResolveDependenciesWithAutoWiringWith3Arguments),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith4Arguments", testThatItUsesTagToResolveDependenciesWithAutoWiringWith4Arguments),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith5Arguments", testThatItUsesTagToResolveDependenciesWithAutoWiringWith5Arguments),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith6Arguments", testThatItUsesTagToResolveDependenciesWithAutoWiringWith6Arguments),
|
||||
("testThatItCanAutoWireOptional", testThatItCanAutoWireOptional)
|
||||
]
|
||||
}()
|
||||
|
||||
override func setUp() {
|
||||
container.reset()
|
||||
}
|
||||
@@ -112,7 +88,7 @@ class AutoWiringTests: XCTestCase {
|
||||
//2 args
|
||||
var factoryWithMostNumberOfArgumentsCalled = false
|
||||
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
|
||||
.resolvingProperties { _ in
|
||||
.resolvingProperties { _,_ in
|
||||
factoryWithMostNumberOfArgumentsCalled = true
|
||||
}
|
||||
|
||||
@@ -138,12 +114,10 @@ class AutoWiringTests: XCTestCase {
|
||||
container.register { ServiceImp2() }
|
||||
|
||||
//when
|
||||
AssertThrows(expression: try container.resolve() as AutoWiredClient) { error -> Bool in
|
||||
switch error {
|
||||
case let DipError.autoWiringFailed(_, error):
|
||||
if case DipError.ambiguousDefinitions = error { return true }
|
||||
else { return false }
|
||||
default: return false
|
||||
XCTAssertThrowsError(try self.container.resolve() as AutoWiredClient) { (error) in
|
||||
guard case DipError.autoWiringFailed(_, DipError.ambiguousDefinitions) = error else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,7 +138,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
|
||||
}
|
||||
|
||||
@@ -189,7 +163,7 @@ class AutoWiringTests: XCTestCase {
|
||||
|
||||
//1 arg tagged
|
||||
var taggedFactoryCalled = false
|
||||
container.register(tag: "tag") { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }.resolvingProperties { _ in
|
||||
container.register(tag: "tag") { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }.resolvingProperties { _,_ in
|
||||
taggedFactoryCalled = true
|
||||
}
|
||||
|
||||
@@ -208,7 +182,7 @@ class AutoWiringTests: XCTestCase {
|
||||
|
||||
//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
|
||||
}
|
||||
|
||||
@@ -233,8 +207,12 @@ class AutoWiringTests: XCTestCase {
|
||||
|
||||
//when
|
||||
let service = try! container.resolve() as Service
|
||||
AssertThrows(expression: try container.resolve(arguments: service) as AutoWiredClient,
|
||||
"Container should not use auto-wiring when resolving with runtime arguments")
|
||||
|
||||
// then
|
||||
XCTAssertThrowsError(
|
||||
try self.container.resolve(arguments: service) as AutoWiredClient,
|
||||
"Container should not use auto-wiring when resolving with runtime arguments"
|
||||
)
|
||||
}
|
||||
|
||||
func testThatItDoesNotUseAutoWiringWhenFailedToResolveLowLevelDependency() {
|
||||
@@ -259,12 +237,13 @@ class AutoWiringTests: XCTestCase {
|
||||
container.register { ServiceImp2() }
|
||||
|
||||
//then
|
||||
AssertThrows(expression: try container.resolve() as AutoWiredClient,
|
||||
"Container should not use auto-wiring when definition for resolved type is registered.")
|
||||
XCTAssertThrowsError(
|
||||
try self.container.resolve() as AutoWiredClient,
|
||||
"Container should not use auto-wiring when definition for resolved type is registered."
|
||||
)
|
||||
}
|
||||
|
||||
func testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgain() {
|
||||
|
||||
//given
|
||||
container.register { ServiceImp1() as Service }
|
||||
container.register { ServiceImp2() }
|
||||
@@ -282,8 +261,10 @@ class AutoWiringTests: XCTestCase {
|
||||
let resolved = try! container.resolve() as AutoWiredClient
|
||||
|
||||
//then
|
||||
//when doing another auto-wiring during resolve we should reuse instance
|
||||
XCTAssertTrue((resolved as! AutoWiredClientImp) === (anotherInstance as! AutoWiredClientImp))
|
||||
XCTAssertTrue(
|
||||
(resolved as! AutoWiredClientImp) === (anotherInstance as! AutoWiredClientImp),
|
||||
"when doing another auto-wiring during resolve we should reuse instance"
|
||||
)
|
||||
}
|
||||
|
||||
func testThatItReusesInstancesResolvedWithoutAutoWiringWhenUsingAutoWiringAgain() {
|
||||
@@ -307,8 +288,10 @@ class AutoWiringTests: XCTestCase {
|
||||
let resolved = try! container.resolve(arguments: service1, service2) as AutoWiredClient
|
||||
|
||||
//then
|
||||
//when doing another auto-wiring during resolve we should reuse instance
|
||||
XCTAssertTrue((resolved as! AutoWiredClientImp) === (anotherInstance as! AutoWiredClientImp))
|
||||
XCTAssertTrue(
|
||||
(resolved as! AutoWiredClientImp) === (anotherInstance as! AutoWiredClientImp),
|
||||
"when doing another auto-wiring during resolve we should reuse instance"
|
||||
)
|
||||
}
|
||||
|
||||
func testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithTheSameTag() {
|
||||
@@ -330,8 +313,10 @@ class AutoWiringTests: XCTestCase {
|
||||
let resolved = try! container.resolve(tag: "tag") as AutoWiredClient
|
||||
|
||||
//then
|
||||
//when doing another auto-wiring during resolve we should reuse instance
|
||||
XCTAssertTrue((resolved as! AutoWiredClientImp) === (anotherInstance as! AutoWiredClientImp))
|
||||
XCTAssertTrue(
|
||||
(resolved as! AutoWiredClientImp) === (anotherInstance as! AutoWiredClientImp),
|
||||
"when doing another auto-wiring during resolve we should reuse instance"
|
||||
)
|
||||
}
|
||||
|
||||
func testThatItDoesNotReuseInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithAnotherTag() {
|
||||
@@ -353,8 +338,10 @@ class AutoWiringTests: XCTestCase {
|
||||
let resolved = try! container.resolve(tag: "tag") as AutoWiredClient
|
||||
|
||||
//then
|
||||
//when doing another auto-wiring during resolve we should reuse instance
|
||||
XCTAssertTrue((resolved as! AutoWiredClientImp) !== (anotherInstance as! AutoWiredClientImp))
|
||||
XCTAssertTrue(
|
||||
(resolved as! AutoWiredClientImp) !== (anotherInstance as! AutoWiredClientImp),
|
||||
"when doing another auto-wiring during resolve we should reuse instance"
|
||||
)
|
||||
}
|
||||
|
||||
func testThatItUsesTagToResolveDependenciesWithAutoWiringWith1Argument() {
|
||||
@@ -464,19 +451,11 @@ class AutoWiringTests: XCTestCase {
|
||||
|
||||
var resolved: AutoWiredClient?
|
||||
//when
|
||||
AssertNoThrow(expression: resolved = try container.resolve() as AutoWiredClient?)
|
||||
XCTAssertNoThrow(resolved = try self.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!)
|
||||
XCTAssertNoThrow(resolved = try self.container.resolve(tag: "tag") as AutoWiredClient?)
|
||||
XCTAssertNotNil(resolved)
|
||||
}
|
||||
|
||||
|
||||
@@ -47,27 +47,6 @@ class ComponentScopeTests: XCTestCase {
|
||||
|
||||
let container = DependencyContainer()
|
||||
|
||||
static var allTests = {
|
||||
return [
|
||||
("testThatSharedIsDefaultScope", testThatSharedIsDefaultScope),
|
||||
("testThatScopeCanBeChanged", testThatScopeCanBeChanged),
|
||||
("testThatItResolvesTypeAsNewInstanceForUniqueScope", testThatItResolvesTypeAsNewInstanceForUniqueScope),
|
||||
("testThatItReusesInstanceForSingletonScope", testThatItReusesInstanceForSingletonScope),
|
||||
("testThatSingletonIsNotReusedAcrossContainers", testThatSingletonIsNotReusedAcrossContainers),
|
||||
("testThatSingletonIsReleasedWhenDefinitionIsRemoved", testThatSingletonIsReleasedWhenDefinitionIsRemoved),
|
||||
("testThatSingletonIsReleasedWhenDefinitionIsOverridden", testThatSingletonIsReleasedWhenDefinitionIsOverridden),
|
||||
("testThatSingletonIsReleasedWhenContainerIsReset", testThatSingletonIsReleasedWhenContainerIsReset),
|
||||
("testThatItReusesInstanceInSharedScopeDuringResolve", testThatItReusesInstanceInSharedScopeDuringResolve),
|
||||
("testThatItDoesNotReuseInstanceInSharedScopeInNextResolve", testThatItDoesNotReuseInstanceInSharedScopeInNextResolve),
|
||||
("testThatItDoesNotReuseInstanceInSharedScopeResolvedForNilTag", testThatItDoesNotReuseInstanceInSharedScopeResolvedForNilTagWhenResolvingForAnotherTag),
|
||||
("testThatItReusesInstanceInSharedScopeResolvedForNilTag", testThatItReusesInstanceInSharedScopeResolvedForNilTag),
|
||||
("testThatItReusesResolvedInstanceWhenResolvingOptional", testThatItReusesResolvedInstanceWhenResolvingOptional),
|
||||
("testThatItHoldsWeakReferenceToWeakSingletonInstance", testThatItHoldsWeakReferenceToWeakSingletonInstance),
|
||||
("testThatItResolvesWeakSingletonAgainAfterItWasReleased", testThatItResolvesWeakSingletonAgainAfterItWasReleased),
|
||||
("testThatCollaboratingContainersReuseSingletonsResolvedByAnotherContainer", testThatCollaboratingContainersReuseSingletonsResolvedByAnotherContainer)
|
||||
]
|
||||
}()
|
||||
|
||||
override func setUp() {
|
||||
container.reset()
|
||||
}
|
||||
@@ -301,23 +280,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() {
|
||||
@@ -347,7 +320,10 @@ class ComponentScopeTests: XCTestCase {
|
||||
_ = try? container.resolve() as ServiceImp1
|
||||
|
||||
//then
|
||||
AssertNoThrow(expression: try container.resolve() as Service, "Weak singleton should be resolved again.")
|
||||
XCTAssertNoThrow(
|
||||
try container.resolve() as Service,
|
||||
"Weak singleton should be resolved again."
|
||||
)
|
||||
}
|
||||
|
||||
func testThatCollaboratingContainersReuseSingletonsResolvedByAnotherContainer() {
|
||||
|
||||
@@ -39,20 +39,6 @@ class ContextTests: XCTestCase {
|
||||
|
||||
let container = DependencyContainer()
|
||||
|
||||
static var allTests = {
|
||||
return [
|
||||
("testThatContextStoresCurrentlyResolvedType", testThatContextStoresCurrentlyResolvedType),
|
||||
("testThatContextStoresInjectedInType", testThatContextStoresInjectedInType),
|
||||
("testThatContextStoresTheTagPassedToResolve", testThatContextStoresTheTagPassedToResolve),
|
||||
("testThatContextStoresTheTagPassedToResolveWhenAutoInjecting", testThatContextStoresTheTagPassedToResolveWhenAutoInjecting),
|
||||
("testThatContextStoresTheTagPassedToResolveWhenAutoWiring", testThatContextStoresTheTagPassedToResolveWhenAutoWiring),
|
||||
("testThatContextDoesNotOverrideNilTagPassedToResolve", testThatContextDoesNotOverrideNilTagPassedToResolve),
|
||||
("testThatContextStoresNameOfAutoInjectedProperty", testThatContextStoresNameOfAutoInjectedProperty),
|
||||
("testThatItDoesNotSetInjectedInTypeWhenResolvingWithCollaboration", testThatItDoesNotSetInjectedInTypeWhenResolvingWithCollaboration),
|
||||
("testThatContextIsPreservedWhenResolvingWithCollaboration", testThatContextIsPreservedWhenResolvingWithCollaboration)
|
||||
]
|
||||
}()
|
||||
|
||||
override func setUp() {
|
||||
container.reset()
|
||||
container.register { ServiceImp2() }
|
||||
@@ -63,7 +49,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 +57,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 +69,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 +77,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 +90,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 +100,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 +121,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 +135,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 +146,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 +167,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 +176,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 +193,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 +225,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 +233,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)
|
||||
}
|
||||
|
||||
|
||||
@@ -36,18 +36,6 @@ class DefinitionTests: XCTestCase {
|
||||
let tag1 = DependencyContainer.Tag.String("tag1")
|
||||
let tag2 = DependencyContainer.Tag.String("tag2")
|
||||
|
||||
static var allTests = {
|
||||
return [
|
||||
("testThatDefinitionKeyIsEqualBy_Type_Factory_Tag", testThatDefinitionKeyIsEqualBy_Type_Factory_Tag),
|
||||
("testThatDefinitionKeysWithDifferentTypesAreNotEqual", testThatDefinitionKeysWithDifferentTypesAreNotEqual),
|
||||
("testThatDefinitionKeysWithDifferentFactoriesAreNotEqual", testThatDefinitionKeysWithDifferentFactoriesAreNotEqual),
|
||||
("testThatDefinitionKeysWithDifferentTagsAreNotEqual", testThatDefinitionKeysWithDifferentTagsAreNotEqual),
|
||||
("testThatResolveDependenciesCallsResolveDependenciesBlock", testThatResolveDependenciesCallsResolveDependenciesBlock),
|
||||
("testThatResolveDependenciesBlockIsNotCalledWhenPassedWrongInstance", testThatResolveDependenciesBlockIsNotCalledWhenPassedWrongInstance),
|
||||
("testThatItRegisteresOptionalTypesAsForwardedTypes", testThatItRegisteresOptionalTypesAsForwardedTypes)
|
||||
]
|
||||
}()
|
||||
|
||||
func testThatDefinitionKeyIsEqualBy_Type_Factory_Tag() {
|
||||
let equalKey1 = DefinitionKey(type: Service.self, typeOfArguments: F1.self, tag: tag1)
|
||||
let equalKey2 = DefinitionKey(type: Service.self, typeOfArguments: F1.self, tag: tag1)
|
||||
@@ -116,7 +104,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 }))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+233
-122
@@ -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 }
|
||||
@@ -49,30 +49,6 @@ class DipTests: XCTestCase {
|
||||
|
||||
let container = DependencyContainer()
|
||||
|
||||
static var allTests = {
|
||||
return [
|
||||
("testThatCreatingContainerWithConfigBlockDoesNotCreateRetainCycle", testThatCreatingContainerWithConfigBlockDoesNotCreateRetainCycle),
|
||||
("testThatItResolvesInstanceRegisteredWithoutTag", testThatItResolvesInstanceRegisteredWithoutTag),
|
||||
("testThatItResolvesInstanceRegisteredWithTag", testThatItResolvesInstanceRegisteredWithTag),
|
||||
("testThatItResolvesDifferentInstancesRegisteredForDifferentTags", testThatItResolvesDifferentInstancesRegisteredForDifferentTags),
|
||||
("testThatNewRegistrationOverridesPreviousRegistration", testThatNewRegistrationOverridesPreviousRegistration),
|
||||
("testThatItCallsResolveDependenciesOnDefinition", testThatItCallsResolveDependenciesOnDefinition),
|
||||
("testThatItThrowsErrorIfCanNotFindDefinitionForType", testThatItThrowsErrorIfCanNotFindDefinitionForType),
|
||||
("testThatItThrowsErrorIfCanNotFindDefinitionForTag", testThatItThrowsErrorIfCanNotFindDefinitionForTag),
|
||||
("testThatItThrowsErrorIfCanNotFindDefinitionForFactoryWithArguments", testThatItThrowsErrorIfCanNotFindDefinitionForFactoryWithArguments),
|
||||
("testThatItThrowsErrorIfConstructorThrows", testThatItThrowsErrorIfConstructorThrows),
|
||||
("testThatItThrowsErrorIfFailsToResolveDependency", testThatItThrowsErrorIfFailsToResolveDependency),
|
||||
("testThatItCallsDidResolveDependenciesOnResolvableIntance", testThatItCallsDidResolveDependenciesOnResolvableIntance),
|
||||
("testThatItCallsDidResolveDependenciesInReverseOrder", testThatItCallsDidResolveDependenciesInReverseOrder),
|
||||
("testItCallsResolveDependenciesOnResolableInstance", testItCallsResolveDependenciesOnResolableInstance),
|
||||
("testThatItResolvesCircularDependencies", testThatItResolvesCircularDependencies),
|
||||
("testThatItCanResolveUsingContainersCollaboration", testThatItCanResolveUsingContainersCollaboration),
|
||||
("testThatCollaboratingWithSelfIsIgnored", testThatCollaboratingWithSelfIsIgnored),
|
||||
("testThatCollaboratingContainersAreWeakReferences", testThatCollaboratingContainersAreWeakReferences),
|
||||
("testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer", testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer),
|
||||
]
|
||||
}()
|
||||
|
||||
override func setUp() {
|
||||
container.reset()
|
||||
}
|
||||
@@ -123,12 +99,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 +122,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 +152,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,38 +197,34 @@ class DipTests: XCTestCase {
|
||||
XCTAssertTrue(resolveDependenciesCalled)
|
||||
|
||||
resolveDependenciesCalled = false
|
||||
|
||||
//and when
|
||||
let _ = try! container.resolve((Service!).self)
|
||||
|
||||
//then
|
||||
XCTAssertTrue(resolveDependenciesCalled)
|
||||
}
|
||||
|
||||
|
||||
func testThatItThrowsErrorIfCanNotFindDefinitionForType() {
|
||||
//given
|
||||
container.register { ServiceImp1() as ServiceImp1 }
|
||||
|
||||
//when
|
||||
AssertThrows(expression: try container.resolve() as Service) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else { return false }
|
||||
XCTAssertThrowsError(try self.container.resolve() as Service) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
//then
|
||||
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: Void.self, tag: nil)
|
||||
XCTAssertEqual(key, expectedKey)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//and when
|
||||
AssertThrows(expression: try container.resolve(Service.self)) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else { return false }
|
||||
XCTAssertThrowsError(try self.container.resolve(Service.self)) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
//then
|
||||
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: Void.self, tag: nil)
|
||||
XCTAssertEqual(key, expectedKey)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,25 +233,27 @@ class DipTests: XCTestCase {
|
||||
container.register(tag: "some tag") { ServiceImp1() as Service }
|
||||
|
||||
//when
|
||||
AssertThrows(expression: try container.resolve(tag: "other tag") as Service) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else { return false }
|
||||
XCTAssertThrowsError(try self.container.resolve(tag: "other tag") as Service) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
//then
|
||||
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: Void.self, tag: "other tag")
|
||||
XCTAssertEqual(key, expectedKey)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//and when
|
||||
AssertThrows(expression: try container.resolve(Service.self, tag: "other tag")) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else { return false }
|
||||
XCTAssertThrowsError(try self.container.resolve(Service.self, tag: "other tag")) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
//then
|
||||
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: Void.self, tag: "other tag")
|
||||
XCTAssertEqual(key, expectedKey)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,25 +262,27 @@ class DipTests: XCTestCase {
|
||||
container.register { ServiceImp1() as Service }
|
||||
|
||||
//when
|
||||
AssertThrows(expression: try container.resolve(arguments: "some string") as Service) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else { return false }
|
||||
XCTAssertThrowsError(try self.container.resolve(arguments: "some string") as Service) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
//then
|
||||
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: String.self, tag: nil)
|
||||
XCTAssertEqual(key, expectedKey)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//and when
|
||||
AssertThrows(expression: try container.resolve(Service.self, arguments: "some string")) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else { return false }
|
||||
XCTAssertThrowsError(try self.container.resolve(Service.self, arguments: "some string")) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
//then
|
||||
let expectedKey = DefinitionKey(type: Service.self, typeOfArguments: String.self, tag: nil)
|
||||
XCTAssertEqual(key, expectedKey)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,18 +293,18 @@ class DipTests: XCTestCase {
|
||||
container.register { () throws -> Service in throw expectedError }
|
||||
|
||||
//when
|
||||
AssertThrows(expression: try container.resolve() as Service) { error in
|
||||
switch error {
|
||||
case let DipError.definitionNotFound(key) where key == failedKey: return true
|
||||
default: return false
|
||||
XCTAssertThrowsError(try self.container.resolve() as Service) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error, key == failedKey else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//and when
|
||||
AssertThrows(expression: try container.resolve(Service.self)) { error in
|
||||
switch error {
|
||||
case let DipError.definitionNotFound(key) where key == failedKey: return true
|
||||
default: return false
|
||||
XCTAssertThrowsError(try self.container.resolve(Service.self)) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error, key == failedKey else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,18 +320,18 @@ class DipTests: XCTestCase {
|
||||
}
|
||||
|
||||
//when
|
||||
AssertThrows(expression: try container.resolve() as Service) { error in
|
||||
switch error {
|
||||
case let DipError.definitionNotFound(key) where key == failedKey: return true
|
||||
default: return false
|
||||
XCTAssertThrowsError(try self.container.resolve() as Service) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error, key == failedKey else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//and when
|
||||
AssertThrows(expression: try container.resolve(Service.self)) { error in
|
||||
switch error {
|
||||
case let DipError.definitionNotFound(key) where key == failedKey: return true
|
||||
default: return false
|
||||
XCTAssertThrowsError(try self.container.resolve(Service.self)) { error in
|
||||
guard case let DipError.definitionNotFound(key) = error, key == failedKey else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -520,22 +476,15 @@ class DipTests: XCTestCase {
|
||||
XCTAssertNotNil(self.server?.client)
|
||||
XCTAssertNotNil(self.secondServer?.client)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//given
|
||||
container.register { try ResolvableServer(client: self.container.resolve()) as Server }
|
||||
.resolvingProperties { (container: DependencyContainer, server: Server) in
|
||||
let server = server as! ResolvableServer
|
||||
server.secondClient = try container.resolve() as Client
|
||||
}
|
||||
.resolvingProperty(\ResolvableServer.secondClient, as: Client.self)
|
||||
|
||||
container.register { ResolvableClient() as Client }
|
||||
.resolvingProperties { (container: DependencyContainer, client: Client) in
|
||||
let client = client as! ResolvableClient
|
||||
client.server = try container.resolve() as Server
|
||||
client.secondServer = try container.resolve() as Server
|
||||
}
|
||||
.resolvingProperty(\ResolvableClient.server, factory: { try $0.resolve() })
|
||||
.resolvingProperty(\ResolvableClient.secondServer)
|
||||
|
||||
//when
|
||||
let client = (try! container.resolve() as Client) as! ResolvableClient
|
||||
@@ -573,17 +522,17 @@ 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
|
||||
}
|
||||
|
||||
//then
|
||||
AssertNoThrow(expression: try container.validate("arg"))
|
||||
XCTAssertNoThrow(try self.container.validate("arg"))
|
||||
XCTAssertTrue(createdService1)
|
||||
XCTAssertTrue(createdService2)
|
||||
XCTAssertTrue(createdService3)
|
||||
@@ -606,8 +555,8 @@ class DipTests: XCTestCase {
|
||||
}
|
||||
|
||||
//then
|
||||
AssertNoThrow(expression:
|
||||
try container.validate(
|
||||
XCTAssertNoThrow(
|
||||
try self.container.validate(
|
||||
"1",
|
||||
expectedIntArgument,
|
||||
"x",
|
||||
@@ -622,8 +571,18 @@ class DipTests: XCTestCase {
|
||||
container.register { (a: Int) -> Service in ServiceImp1() as Service }
|
||||
|
||||
//then
|
||||
AssertThrows(expression: try container.validate()) { error in error is DipError }
|
||||
AssertThrows(expression: try container.validate("1")) { error in error is DipError }
|
||||
XCTAssertThrowsError(try self.container.validate()) { error in
|
||||
guard error is DipError else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
XCTAssertThrowsError(try self.container.validate("1")) { error in
|
||||
guard error is DipError else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testThatItFailsValidationOnlyForDipErrors() {
|
||||
@@ -635,7 +594,7 @@ class DipTests: XCTestCase {
|
||||
}
|
||||
|
||||
//then
|
||||
AssertNoThrow(expression: try container.validate())
|
||||
XCTAssertNoThrow(try self.container.validate())
|
||||
|
||||
//given
|
||||
let key = DefinitionKey(type: Service.self, typeOfArguments: Void.self, tag: nil)
|
||||
@@ -644,9 +603,11 @@ class DipTests: XCTestCase {
|
||||
}
|
||||
|
||||
//then
|
||||
AssertThrows(expression: try container.validate()) { error in
|
||||
if case let DipError.definitionNotFound(_key) = error, _key == key { return true }
|
||||
else { return false }
|
||||
XCTAssertThrowsError(try self.container.validate()) { error in
|
||||
guard case let DipError.definitionNotFound(_key) = error, _key == key else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,10 +625,10 @@ extension DipTests {
|
||||
container.collaborate(with: collaborator)
|
||||
|
||||
//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))
|
||||
XCTAssertNoThrow(try self.container.resolve() as Service)
|
||||
XCTAssertNoThrow(try self.container.resolve(Service.self))
|
||||
XCTAssertNoThrow(try collaborator.resolve() as String)
|
||||
XCTAssertNoThrow(try collaborator.resolve(String.self))
|
||||
}
|
||||
|
||||
func testThatCollaboratingWithSelfIsIgnored() {
|
||||
@@ -743,16 +704,16 @@ extension DipTests {
|
||||
let collaborator4 = DependencyContainer()
|
||||
|
||||
collaborator1.collaborate(with: container)
|
||||
XCTAssertTrue(collaborator1.resolvedInstances.singletonsBox === container.resolvedInstances.singletonsBox)
|
||||
XCTAssertTrue(collaborator1.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
|
||||
|
||||
collaborator2.collaborate(with: container)
|
||||
XCTAssertTrue(collaborator2.resolvedInstances.singletonsBox === container.resolvedInstances.singletonsBox)
|
||||
XCTAssertTrue(collaborator2.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
|
||||
|
||||
collaborator3.collaborate(with: collaborator1)
|
||||
XCTAssertTrue(collaborator3.resolvedInstances.singletonsBox === container.resolvedInstances.singletonsBox)
|
||||
XCTAssertTrue(collaborator3.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
|
||||
|
||||
collaborator4.collaborate(with: collaborator2)
|
||||
XCTAssertTrue(collaborator4.resolvedInstances.singletonsBox === container.resolvedInstances.singletonsBox)
|
||||
XCTAssertTrue(collaborator4.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
|
||||
|
||||
let service1 = try! collaborator1.resolve() as Service
|
||||
let service2 = try! collaborator2.resolve() as Service
|
||||
@@ -760,10 +721,160 @@ extension DipTests {
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension DipTests {
|
||||
// https://bugs.swift.org/browse/SR-8878
|
||||
func test_weak_mirror_regression() {
|
||||
class A {
|
||||
static var released = false
|
||||
deinit {
|
||||
A.released = true
|
||||
}
|
||||
}
|
||||
class B {
|
||||
static var released = false
|
||||
weak var a: A?
|
||||
init(a: A) {
|
||||
self.a = a
|
||||
}
|
||||
deinit {
|
||||
B.released = true
|
||||
}
|
||||
}
|
||||
let container = DependencyContainer()
|
||||
let tag = "my_tag"
|
||||
container.register(.unique, tag: tag, factory: B.init(a:))
|
||||
do {
|
||||
let a0 = A()
|
||||
let _: B = try container.resolve(tag: tag, arguments: a0)
|
||||
|
||||
|
||||
XCTAssertTrue(B.released)
|
||||
// Due to regression in swift 4.2 Mirror retains weak children
|
||||
// https://bugs.swift.org/browse/SR-8878
|
||||
XCTAssertFalse(A.released)
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -51,22 +51,6 @@ class RuntimeArgumentsTests: XCTestCase {
|
||||
|
||||
let container = DependencyContainer()
|
||||
|
||||
static var allTests = {
|
||||
return [
|
||||
("testThatItResolvesInstanceWithOneArgument", testThatItResolvesInstanceWithOneArgument),
|
||||
("testThatItResolvesInstanceWithTwoArguments", testThatItResolvesInstanceWithTwoArguments),
|
||||
("testThatItResolvesInstanceWithThreeArguments", testThatItResolvesInstanceWithThreeArguments),
|
||||
("testThatItResolvesInstanceWithFourArguments", testThatItResolvesInstanceWithFourArguments),
|
||||
("testThatItResolvesInstanceWithFiveArguments", testThatItResolvesInstanceWithFiveArguments),
|
||||
("testThatItResolvesInstanceWithSixArguments", testThatItResolvesInstanceWithSixArguments),
|
||||
("testThatItRegistersDifferentFactoriesForDifferentNumberOfArguments", testThatItRegistersDifferentFactoriesForDifferentNumberOfArguments),
|
||||
("testThatItRegistersDifferentFactoriesForDifferentTypesOfArguments", testThatItRegistersDifferentFactoriesForDifferentTypesOfArguments),
|
||||
("testThatItRegistersDifferentFactoriesForDifferentOrderOfArguments", testThatItRegistersDifferentFactoriesForDifferentOrderOfArguments),
|
||||
("testThatNewRegistrationWithSameArgumentsOverridesPreviousRegistration", testThatNewRegistrationWithSameArgumentsOverridesPreviousRegistration),
|
||||
("testThatDifferentFactoriesRegisteredIfArgumentIsOptional", testThatDifferentFactoriesRegisteredIfArgumentIsOptional)
|
||||
]
|
||||
}()
|
||||
|
||||
override func setUp() {
|
||||
container.reset()
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if canImport(ObjectiveC)
|
||||
import XCTest
|
||||
@testable import Dip
|
||||
|
||||
@@ -48,8 +49,8 @@ private class ServerImp: Server, Hashable {
|
||||
weak var client: Client!
|
||||
init() {}
|
||||
|
||||
var hashValue: Int {
|
||||
return Unmanaged.passUnretained(self).toOpaque().hashValue
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(ObjectIdentifier(self))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,22 +63,6 @@ private var resolvedClients = Array<ClientImp>()
|
||||
|
||||
private var container: DependencyContainer!
|
||||
|
||||
#if os(Linux)
|
||||
import Glibc
|
||||
|
||||
private var runningThreads: Int = 0
|
||||
private var lock: pthread_spinlock_t = 0
|
||||
|
||||
private let resolveClientSync: () -> Client? = {
|
||||
let pointer = dispatch_sync { _ in
|
||||
let resolved = try! container.resolve() as Client
|
||||
return UnsafeMutableRawPointer(Unmanaged.passRetained(resolved as! ClientImp).toOpaque())
|
||||
}
|
||||
guard let clientPointer = pointer else { return nil }
|
||||
return Unmanaged<ClientImp>.fromOpaque(clientPointer).takeRetainedValue()
|
||||
}
|
||||
|
||||
#else
|
||||
let queue = OperationQueue()
|
||||
let lock = RecursiveLock()
|
||||
|
||||
@@ -88,18 +73,11 @@ private let resolveClientSync: () -> Client? = {
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
let resolveServerAsync = {
|
||||
let server = try! container.resolve() as Server
|
||||
lock.lock()
|
||||
resolvedServers.insert(server as! ServerImp)
|
||||
|
||||
#if os(Linux)
|
||||
runningThreads -= 1
|
||||
#endif
|
||||
|
||||
lock.unlock()
|
||||
}
|
||||
|
||||
@@ -107,31 +85,11 @@ let resolveClientAsync = {
|
||||
let client = try! container.resolve() as Client
|
||||
lock.lock()
|
||||
resolvedClients.append(client as! ClientImp)
|
||||
|
||||
#if os(Linux)
|
||||
runningThreads -= 1
|
||||
#endif
|
||||
|
||||
lock.unlock()
|
||||
}
|
||||
|
||||
class ThreadSafetyTests: XCTestCase {
|
||||
|
||||
#if os(Linux)
|
||||
required init(name: String, testClosure: @escaping (XCTestCase) throws -> Void) {
|
||||
pthread_spin_init(&lock, 0)
|
||||
super.init(name: name, testClosure: testClosure)
|
||||
}
|
||||
#endif
|
||||
|
||||
static var allTests = {
|
||||
return [
|
||||
("testSingletonThreadSafety", testSingletonThreadSafety),
|
||||
("testFactoryThreadSafety", testFactoryThreadSafety),
|
||||
("testCircularReferenceThreadSafety", testCircularReferenceThreadSafety)
|
||||
]
|
||||
}()
|
||||
|
||||
override func setUp() {
|
||||
Dip.logLevel = .Verbose
|
||||
container = DependencyContainer()
|
||||
@@ -146,25 +104,10 @@ class ThreadSafetyTests: XCTestCase {
|
||||
container.register(.singleton) { ServerImp() as Server }
|
||||
|
||||
for _ in 0..<100 {
|
||||
#if os(Linux)
|
||||
lock.lock()
|
||||
runningThreads += 1
|
||||
lock.unlock()
|
||||
|
||||
dispatch_async { _ in
|
||||
resolveServerAsync()
|
||||
return nil
|
||||
}
|
||||
#else
|
||||
queue.addOperation(resolveServerAsync)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(Linux)
|
||||
while runningThreads > 0 { sleep(1) }
|
||||
#else
|
||||
queue.waitUntilAllOperationsAreFinished()
|
||||
#endif
|
||||
|
||||
XCTAssertEqual(resolvedServers.count, 1, "Should create only one instance")
|
||||
}
|
||||
@@ -174,25 +117,10 @@ class ThreadSafetyTests: XCTestCase {
|
||||
container.register { ServerImp() as Server }
|
||||
|
||||
for _ in 0..<100 {
|
||||
#if os(Linux)
|
||||
lock.lock()
|
||||
runningThreads += 1
|
||||
lock.unlock()
|
||||
|
||||
dispatch_async { _ in
|
||||
resolveServerAsync()
|
||||
return nil
|
||||
}
|
||||
#else
|
||||
queue.addOperation(resolveServerAsync)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(Linux)
|
||||
while runningThreads > 0 { sleep(1) }
|
||||
#else
|
||||
queue.waitUntilAllOperationsAreFinished()
|
||||
#endif
|
||||
|
||||
XCTAssertEqual(resolvedServers.count, 100, "All instances should be different")
|
||||
}
|
||||
@@ -209,25 +137,10 @@ class ThreadSafetyTests: XCTestCase {
|
||||
}
|
||||
|
||||
for _ in 0..<100 {
|
||||
#if os(Linux)
|
||||
lock.lock()
|
||||
runningThreads += 1
|
||||
lock.unlock()
|
||||
|
||||
dispatch_async { _ in
|
||||
resolveClientAsync()
|
||||
return nil
|
||||
}
|
||||
#else
|
||||
queue.addOperation(resolveClientAsync)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(Linux)
|
||||
while runningThreads > 0 { sleep(1) }
|
||||
#else
|
||||
queue.waitUntilAllOperationsAreFinished()
|
||||
#endif
|
||||
|
||||
XCTAssertEqual(resolvedClients.count, 100, "Instances should be not reused in different object graphs")
|
||||
for client in resolvedClients {
|
||||
@@ -238,5 +151,4 @@ class ThreadSafetyTests: XCTestCase {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,29 +27,36 @@ import XCTest
|
||||
|
||||
private protocol Service: class { }
|
||||
private protocol ForwardedType: class { }
|
||||
#if os(Linux)
|
||||
private class ServiceImp1: Service, ForwardedType { }
|
||||
private class ServiceImp2: Service, ForwardedType { }
|
||||
#else
|
||||
private class ServiceImp1: NSObject, Service, ForwardedType { }
|
||||
private class ServiceImp2: NSObject, Service, ForwardedType { }
|
||||
#endif
|
||||
|
||||
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()
|
||||
|
||||
static var allTests = {
|
||||
return [
|
||||
("testThatItResolvesInstanceByTypeForwarding", testThatItResolvesInstanceByTypeForwarding),
|
||||
("testThatItReusesInstanceResolvedByTypeForwarding", testThatItReusesInstanceResolvedByTypeForwarding),
|
||||
("testThatItDoesNotResolveByTypeForwardingIfRegisteredForAnotherTag", testThatItDoesNotResolveByTypeForwardingIfRegisteredForAnotherTag),
|
||||
("testThatItDoesNotReuseInstanceResolvedByTypeForwardingRegisteredForAnotherTag", testThatItDoesNotReuseInstanceResolvedByTypeForwardingRegisteredForAnotherTag),
|
||||
("testThatItCallsResolvedDependenciesBlockWhenResolvingByTypeForwarding", testThatItCallsResolvedDependenciesBlockWhenResolvingByTypeForwarding),
|
||||
("testThatItCallsResolvedDependenciesBlockProvidedAfterRegistrationWhenResolvingByTypeForwarding",testThatItCallsResolvedDependenciesBlockProvidedAfterRegistrationWhenResolvingByTypeForwarding),
|
||||
("testThatItFallbackToDefinitionWithNoTagWhenResolvingInstanceByTypeForwarding", testThatItFallbackToDefinitionWithNoTagWhenResolvingInstanceByTypeForwarding),
|
||||
("testThatItCanResolveOptional", testThatItCanResolveOptional),
|
||||
("testThatItFirstUsesTaggedDefinitionWhenResolvingOptional", testThatItFirstUsesTaggedDefinitionWhenResolvingOptional),
|
||||
("testThatItThrowsErrorWhenResolvingNotImplementedTypeWithTypeForwarding", testThatItThrowsErrorWhenResolvingNotImplementedTypeWithTypeForwarding),
|
||||
("testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType", testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType),
|
||||
("testThatItDoesNotOverrideIfDefinitionForwardsTheSameTypeWithDifferentTag", testThatItDoesNotOverrideIfDefinitionForwardsTheSameTypeWithDifferentTag)
|
||||
]
|
||||
}()
|
||||
|
||||
override func setUp() {
|
||||
container.reset()
|
||||
@@ -109,15 +116,15 @@ class TypeForwardingTests: XCTestCase {
|
||||
def.implements(ForwardedType.self, tag: "otherTag")
|
||||
|
||||
//then
|
||||
AssertThrows(expression: try container.resolve(tag: "tag") as ForwardedType)
|
||||
AssertThrows(expression: try container.resolve(ForwardedType.self, tag: "tag"))
|
||||
XCTAssertThrowsError(try self.container.resolve(tag: "tag") as ForwardedType)
|
||||
XCTAssertThrowsError(try self.container.resolve(ForwardedType.self, tag: "tag"))
|
||||
|
||||
//and given
|
||||
def.implements(ForwardedType.self, tag: "tag")
|
||||
|
||||
//then
|
||||
AssertNoThrow(expression: try container.resolve(tag: "tag") as ForwardedType)
|
||||
AssertNoThrow(expression: try container.resolve(ForwardedType.self, tag: "tag"))
|
||||
XCTAssertNoThrow(try self.container.resolve(tag: "tag") as ForwardedType)
|
||||
XCTAssertNoThrow(try self.container.resolve(ForwardedType.self, tag: "tag"))
|
||||
}
|
||||
|
||||
func testThatItDoesNotReuseInstanceResolvedByTypeForwardingRegisteredForAnotherTag() {
|
||||
@@ -154,9 +161,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 +191,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 +259,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")
|
||||
@@ -276,19 +312,23 @@ class TypeForwardingTests: XCTestCase {
|
||||
.implements(ServiceImp2.self)
|
||||
|
||||
//then
|
||||
AssertThrows(expression: try container.resolve() as ServiceImp2) { error in
|
||||
guard case let DipError.invalidType(_, key) = error else { return false }
|
||||
XCTAssertThrowsError(try self.container.resolve() as ServiceImp2) { error in
|
||||
guard case let DipError.invalidType(_, key) = error else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
let expectedKey = DefinitionKey(type: ServiceImp2.self, typeOfArguments: Void.self, tag: nil)
|
||||
XCTAssertEqual(key, expectedKey)
|
||||
return true
|
||||
}
|
||||
AssertThrows(expression: try container.resolve(ServiceImp2.self)) { error in
|
||||
guard case let DipError.invalidType(_, key) = error else { return false }
|
||||
XCTAssertThrowsError(try self.container.resolve(ServiceImp2.self)) { error in
|
||||
guard case let DipError.invalidType(_, key) = error else {
|
||||
XCTFail("Thrown unexpected error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
let expectedKey = DefinitionKey(type: ServiceImp2.self, typeOfArguments: Void.self, tag: nil)
|
||||
XCTAssertEqual(key, expectedKey)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,41 +28,6 @@ import XCTest
|
||||
typealias NSObject = AnyObject
|
||||
#endif
|
||||
|
||||
func AssertThrows<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T) {
|
||||
AssertThrows(file, line: line, expression: expression, "")
|
||||
}
|
||||
|
||||
func AssertThrows<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T, _ message: String) {
|
||||
AssertThrows(expression: expression, checkError: { _ in true }, message)
|
||||
}
|
||||
|
||||
func AssertThrows<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T, checkError: (Error) -> Bool) {
|
||||
AssertThrows(file, line: line, expression: expression, checkError: checkError, "")
|
||||
}
|
||||
|
||||
func AssertThrows<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T, checkError: (Error) -> Bool, _ message: String) {
|
||||
do {
|
||||
let _ = try expression()
|
||||
XCTFail(message, file: file, line: line)
|
||||
}
|
||||
catch {
|
||||
XCTAssertTrue(checkError(error), "Thrown unexpected error: \(error)", file: file, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
func AssertNoThrow<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T) {
|
||||
AssertNoThrow(file, line: line, expression: expression, "")
|
||||
}
|
||||
|
||||
func AssertNoThrow<T>(_ file: StaticString = #file, line: UInt = #line, expression: @autoclosure () throws -> T, _ message: String) {
|
||||
do {
|
||||
let _ = try expression()
|
||||
}
|
||||
catch {
|
||||
XCTFail(message, file: file, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
#if os(Linux)
|
||||
import Glibc
|
||||
typealias TMain = @convention(c) (UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer?
|
||||
@@ -78,7 +43,7 @@ func dispatch_async(block: @escaping TMain) -> pthread_t {
|
||||
}
|
||||
|
||||
func dispatch_sync(block: @escaping TMain) -> UnsafeMutableRawPointer? {
|
||||
var result: UnsafeMutableRawPointer? = UnsafeMutableRawPointer.allocate(bytes: 1, alignedTo: 0)
|
||||
var result: UnsafeMutableRawPointer? = UnsafeMutableRawPointer.allocate(byteCount: 1, alignment: 0)
|
||||
let pid = startThread(block)
|
||||
pthread_join(pid, &result)
|
||||
return result
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import XCTest
|
||||
@testable import DipTests
|
||||
|
||||
XCTMain([
|
||||
testCase(DipTests.allTests),
|
||||
testCase(DefinitionTests.allTests),
|
||||
testCase(RuntimeArgumentsTests.allTests),
|
||||
testCase(ComponentScopeTests.allTests),
|
||||
testCase(AutoInjectionTests.allTests),
|
||||
// testCase(ThreadSafetyTests.allTests),
|
||||
testCase(AutoWiringTests.allTests),
|
||||
testCase(ContextTests.allTests),
|
||||
testCase(TypeForwardingTests.allTests)
|
||||
])
|
||||
@@ -0,0 +1,202 @@
|
||||
#if !canImport(ObjectiveC)
|
||||
import XCTest
|
||||
|
||||
extension AutoInjectionTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__AutoInjectionTests = [
|
||||
("testThatItAutoInjectsPropertyWithCollaboratingContainer", testThatItAutoInjectsPropertyWithCollaboratingContainer),
|
||||
("testThatItAutoInjectsWhenOverridenInDefinition", testThatItAutoInjectsWhenOverridenInDefinition),
|
||||
("testThatItCallsDidInjectOnAutoInjectedProperty", testThatItCallsDidInjectOnAutoInjectedProperty),
|
||||
("testThatItCallsResolveDependencyBlockWhenAutoInjecting", testThatItCallsResolveDependencyBlockWhenAutoInjecting),
|
||||
("testThatItDoesNotAutoInjectIfDisabledInContainer", testThatItDoesNotAutoInjectIfDisabledInContainer),
|
||||
("testThatItDoesNotAutoInjectIfDisabledInDefinition", testThatItDoesNotAutoInjectIfDisabledInDefinition),
|
||||
("testThatItDoesNotPassTagToAutoInjectedPropertyWithExplicitTag", testThatItDoesNotPassTagToAutoInjectedPropertyWithExplicitTag),
|
||||
("testThatItPassesTagToAutoInjectedProperty", testThatItPassesTagToAutoInjectedProperty),
|
||||
("testThatItResolvesAutoInjectedDependencies", testThatItResolvesAutoInjectedDependencies),
|
||||
("testThatItResolvesAutoInjectedSingletons", testThatItResolvesAutoInjectedSingletons),
|
||||
("testThatItResolvesInheritedDependencies", testThatItResolvesInheritedDependencies),
|
||||
("testThatItResolvesTaggedAutoInjectedProperties", testThatItResolvesTaggedAutoInjectedProperties),
|
||||
("testThatItReusesAutoInjectedInstancesOnNextResolveOrAutoInjection", testThatItReusesAutoInjectedInstancesOnNextResolveOrAutoInjection),
|
||||
("testThatItReusesResolvedAutoInjectedInstances", testThatItReusesResolvedAutoInjectedInstances),
|
||||
("testThatItThrowsErrorIfFailsToAutoInjectDependency", testThatItThrowsErrorIfFailsToAutoInjectDependency),
|
||||
("testThatNoErrorThrownWhenOptionalPropertiesAreNotAutoInjected", testThatNoErrorThrownWhenOptionalPropertiesAreNotAutoInjected),
|
||||
("testThatThereIsNoRetainCycleBetweenAutoInjectedCircularDependencies", testThatThereIsNoRetainCycleBetweenAutoInjectedCircularDependencies),
|
||||
]
|
||||
}
|
||||
|
||||
extension AutoWiringTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__AutoWiringTests = [
|
||||
("testThatItCanAutoWireOptional", testThatItCanAutoWireOptional),
|
||||
("testThatItCanResolveWithAutoWiring", testThatItCanResolveWithAutoWiring),
|
||||
("testThatItDoesNotReuseInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithAnotherTag", testThatItDoesNotReuseInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithAnotherTag),
|
||||
("testThatItDoesNotTryToUseAutoWiringWhenCallingResolveWithArguments", testThatItDoesNotTryToUseAutoWiringWhenCallingResolveWithArguments),
|
||||
("testThatItDoesNotUseAutoWiringWhenFailedToResolveLowLevelDependency", testThatItDoesNotUseAutoWiringWhenFailedToResolveLowLevelDependency),
|
||||
("testThatItFallbackToNotTaggedFactoryWhenUsingAutoWire", testThatItFallbackToNotTaggedFactoryWhenUsingAutoWire),
|
||||
("testThatItPrefersTaggedFactoryWithDifferentNumberOfArgumentsWhenUsingAutoWire", testThatItPrefersTaggedFactoryWithDifferentNumberOfArgumentsWhenUsingAutoWire),
|
||||
("testThatItPrefersTaggedFactoryWithDifferentTypesOfArgumentsWhenUsingAutoWire", testThatItPrefersTaggedFactoryWithDifferentTypesOfArgumentsWhenUsingAutoWire),
|
||||
("testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgain", testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgain),
|
||||
("testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithTheSameTag", testThatItReusesInstancesResolvedWithAutoWiringWhenUsingAutoWiringAgainWithTheSameTag),
|
||||
("testThatItReusesInstancesResolvedWithoutAutoWiringWhenUsingAutoWiringAgain", testThatItReusesInstancesResolvedWithoutAutoWiringWhenUsingAutoWiringAgain),
|
||||
("testThatItThrowsAmbiguityErrorWhenUsingAutoWire", testThatItThrowsAmbiguityErrorWhenUsingAutoWire),
|
||||
("testThatItUsesAutoWireFactoryWithMostNumberOfArguments", testThatItUsesAutoWireFactoryWithMostNumberOfArguments),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith1Argument", testThatItUsesTagToResolveDependenciesWithAutoWiringWith1Argument),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith2Arguments", testThatItUsesTagToResolveDependenciesWithAutoWiringWith2Arguments),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith3Arguments", testThatItUsesTagToResolveDependenciesWithAutoWiringWith3Arguments),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith4Arguments", testThatItUsesTagToResolveDependenciesWithAutoWiringWith4Arguments),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith5Arguments", testThatItUsesTagToResolveDependenciesWithAutoWiringWith5Arguments),
|
||||
("testThatItUsesTagToResolveDependenciesWithAutoWiringWith6Arguments", testThatItUsesTagToResolveDependenciesWithAutoWiringWith6Arguments),
|
||||
]
|
||||
}
|
||||
|
||||
extension ComponentScopeTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__ComponentScopeTests = [
|
||||
("testThatCollaboratingContainersReuseSingletonsResolvedByAnotherContainer", testThatCollaboratingContainersReuseSingletonsResolvedByAnotherContainer),
|
||||
("testThatContainerCanBeBootstrappedAgainAfterReset", testThatContainerCanBeBootstrappedAgainAfterReset),
|
||||
("testThatItDoesNotReuseInstanceInSharedScopeInNextResolve", testThatItDoesNotReuseInstanceInSharedScopeInNextResolve),
|
||||
("testThatItDoesNotReuseInstanceInSharedScopeResolvedForNilTagWhenResolvingForAnotherTag", testThatItDoesNotReuseInstanceInSharedScopeResolvedForNilTagWhenResolvingForAnotherTag),
|
||||
("testThatItHoldsWeakReferenceToWeakSingletonInstance", testThatItHoldsWeakReferenceToWeakSingletonInstance),
|
||||
("testThatItResolvesTypeAsNewInstanceForUniqueScope", testThatItResolvesTypeAsNewInstanceForUniqueScope),
|
||||
("testThatItResolvesWeakSingletonAgainAfterItWasReleased", testThatItResolvesWeakSingletonAgainAfterItWasReleased),
|
||||
("testThatItReusesInstanceForSingletonScope", testThatItReusesInstanceForSingletonScope),
|
||||
("testThatItReusesInstanceInSharedScopeDuringResolve", testThatItReusesInstanceInSharedScopeDuringResolve),
|
||||
("testThatItReusesInstanceInSharedScopeResolvedForNilTag", testThatItReusesInstanceInSharedScopeResolvedForNilTag),
|
||||
("testThatItReusesResolvedInstanceWhenResolvingOptional", testThatItReusesResolvedInstanceWhenResolvingOptional),
|
||||
("testThatOnlyEagerSingletonIsCreatedWhenContainerIsBootsrapped", testThatOnlyEagerSingletonIsCreatedWhenContainerIsBootsrapped),
|
||||
("testThatScopeCanBeChanged", testThatScopeCanBeChanged),
|
||||
("testThatSharedIsDefaultScope", testThatSharedIsDefaultScope),
|
||||
("testThatSingletonIsNotReusedAcrossContainers", testThatSingletonIsNotReusedAcrossContainers),
|
||||
("testThatSingletonIsReleasedWhenContainerIsReset", testThatSingletonIsReleasedWhenContainerIsReset),
|
||||
("testThatSingletonIsReleasedWhenDefinitionIsOverridden", testThatSingletonIsReleasedWhenDefinitionIsOverridden),
|
||||
("testThatSingletonIsReleasedWhenDefinitionIsRemoved", testThatSingletonIsReleasedWhenDefinitionIsRemoved),
|
||||
]
|
||||
}
|
||||
|
||||
extension ContextTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__ContextTests = [
|
||||
("testThatContextDoesNotOverrideNilTagPassedToResolve", testThatContextDoesNotOverrideNilTagPassedToResolve),
|
||||
("testThatContextIsPreservedWhenResolvingWithCollaboration", testThatContextIsPreservedWhenResolvingWithCollaboration),
|
||||
("testThatContextStoresCurrentlyResolvedType", testThatContextStoresCurrentlyResolvedType),
|
||||
("testThatContextStoresInjectedInType", testThatContextStoresInjectedInType),
|
||||
("testThatContextStoresNameOfAutoInjectedProperty", testThatContextStoresNameOfAutoInjectedProperty),
|
||||
("testThatContextStoresTheTagPassedToResolve", testThatContextStoresTheTagPassedToResolve),
|
||||
("testThatContextStoresTheTagPassedToResolveWhenAutoInjecting", testThatContextStoresTheTagPassedToResolveWhenAutoInjecting),
|
||||
("testThatContextStoresTheTagPassedToResolveWhenAutoWiring", testThatContextStoresTheTagPassedToResolveWhenAutoWiring),
|
||||
("testThatItDoesNotSetInjectedInTypeWhenResolvingWithCollaboration", testThatItDoesNotSetInjectedInTypeWhenResolvingWithCollaboration),
|
||||
]
|
||||
}
|
||||
|
||||
extension DefinitionTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__DefinitionTests = [
|
||||
("testThatDefinitionKeyIsEqualBy_Type_Factory_Tag", testThatDefinitionKeyIsEqualBy_Type_Factory_Tag),
|
||||
("testThatDefinitionKeysWithDifferentFactoriesAreNotEqual", testThatDefinitionKeysWithDifferentFactoriesAreNotEqual),
|
||||
("testThatDefinitionKeysWithDifferentTagsAreNotEqual", testThatDefinitionKeysWithDifferentTagsAreNotEqual),
|
||||
("testThatDefinitionKeysWithDifferentTypesAreNotEqual", testThatDefinitionKeysWithDifferentTypesAreNotEqual),
|
||||
("testThatItRegisteresOptionalTypesAsForwardedTypes", testThatItRegisteresOptionalTypesAsForwardedTypes),
|
||||
("testThatResolveDependenciesBlockIsNotCalledWhenPassedWrongInstance", testThatResolveDependenciesBlockIsNotCalledWhenPassedWrongInstance),
|
||||
("testThatResolveDependenciesCallsResolveDependenciesBlock", testThatResolveDependenciesCallsResolveDependenciesBlock),
|
||||
]
|
||||
}
|
||||
|
||||
extension DipTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__DipTests = [
|
||||
("test_weak_mirror_regression", test_weak_mirror_regression),
|
||||
("testItCallsResolveDependenciesOnResolableInstance", testItCallsResolveDependenciesOnResolableInstance),
|
||||
("testThatCollaboratingContainersAreWeakReferences", testThatCollaboratingContainersAreWeakReferences),
|
||||
("testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer", testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer),
|
||||
("testThatCollaboratingWithSelfIsIgnored", testThatCollaboratingWithSelfIsIgnored),
|
||||
("testThatCollaborationReferencesAreRecursivelyUpdate", testThatCollaborationReferencesAreRecursivelyUpdate),
|
||||
("testThatContainerAutowireBeforeCollaboration", testThatContainerAutowireBeforeCollaboration),
|
||||
("testThatContainersShareTheirSingletonsOnlyWithCollaborators", testThatContainersShareTheirSingletonsOnlyWithCollaborators),
|
||||
("testThatCreatingContainerWithConfigBlockDoesNotCreateRetainCycle", testThatCreatingContainerWithConfigBlockDoesNotCreateRetainCycle),
|
||||
("testThatItCallsDidResolveDependenciesInReverseOrder", testThatItCallsDidResolveDependenciesInReverseOrder),
|
||||
("testThatItCallsDidResolveDependenciesOnResolvableIntance", testThatItCallsDidResolveDependenciesOnResolvableIntance),
|
||||
("testThatItCallsResolveDependenciesOnDefinition", testThatItCallsResolveDependenciesOnDefinition),
|
||||
("testThatItCanHandleSeparateContainersAndTheirCollaboration", testThatItCanHandleSeparateContainersAndTheirCollaboration),
|
||||
("testThatItCanResolveUsingContainersCollaboration", testThatItCanResolveUsingContainersCollaboration),
|
||||
("testThatItFailsValidationIfNoMatchingArgumentsFound", testThatItFailsValidationIfNoMatchingArgumentsFound),
|
||||
("testThatItFailsValidationOnlyForDipErrors", testThatItFailsValidationOnlyForDipErrors),
|
||||
("testThatItPicksRuntimeArgumentsWhenValidatingConfiguration", testThatItPicksRuntimeArgumentsWhenValidatingConfiguration),
|
||||
("testThatItResolvesCircularDependencies", testThatItResolvesCircularDependencies),
|
||||
("testThatItResolvesDifferentInstancesRegisteredForDifferentTags", testThatItResolvesDifferentInstancesRegisteredForDifferentTags),
|
||||
("testThatItResolvesInstanceRegisteredWithoutTag", testThatItResolvesInstanceRegisteredWithoutTag),
|
||||
("testThatItResolvesInstanceRegisteredWithTag", testThatItResolvesInstanceRegisteredWithTag),
|
||||
("testThatItThrowsErrorIfCanNotFindDefinitionForFactoryWithArguments", testThatItThrowsErrorIfCanNotFindDefinitionForFactoryWithArguments),
|
||||
("testThatItThrowsErrorIfCanNotFindDefinitionForTag", testThatItThrowsErrorIfCanNotFindDefinitionForTag),
|
||||
("testThatItThrowsErrorIfCanNotFindDefinitionForType", testThatItThrowsErrorIfCanNotFindDefinitionForType),
|
||||
("testThatItThrowsErrorIfConstructorThrows", testThatItThrowsErrorIfConstructorThrows),
|
||||
("testThatItThrowsErrorIfFailsToResolveDependency", testThatItThrowsErrorIfFailsToResolveDependency),
|
||||
("testThatItValidatesConfiguration", testThatItValidatesConfiguration),
|
||||
("testThatNewRegistrationOverridesPreviousRegistration", testThatNewRegistrationOverridesPreviousRegistration),
|
||||
]
|
||||
}
|
||||
|
||||
extension RuntimeArgumentsTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__RuntimeArgumentsTests = [
|
||||
("testThatDifferentFactoriesRegisteredIfArgumentIsOptional", testThatDifferentFactoriesRegisteredIfArgumentIsOptional),
|
||||
("testThatItRegistersDifferentFactoriesForDifferentNumberOfArguments", testThatItRegistersDifferentFactoriesForDifferentNumberOfArguments),
|
||||
("testThatItRegistersDifferentFactoriesForDifferentOrderOfArguments", testThatItRegistersDifferentFactoriesForDifferentOrderOfArguments),
|
||||
("testThatItRegistersDifferentFactoriesForDifferentTypesOfArguments", testThatItRegistersDifferentFactoriesForDifferentTypesOfArguments),
|
||||
("testThatItResolvesInstanceWithFiveArguments", testThatItResolvesInstanceWithFiveArguments),
|
||||
("testThatItResolvesInstanceWithFourArguments", testThatItResolvesInstanceWithFourArguments),
|
||||
("testThatItResolvesInstanceWithOneArgument", testThatItResolvesInstanceWithOneArgument),
|
||||
("testThatItResolvesInstanceWithSixArguments", testThatItResolvesInstanceWithSixArguments),
|
||||
("testThatItResolvesInstanceWithThreeArguments", testThatItResolvesInstanceWithThreeArguments),
|
||||
("testThatItResolvesInstanceWithTwoArguments", testThatItResolvesInstanceWithTwoArguments),
|
||||
("testThatNewRegistrationWithSameArgumentsOverridesPreviousRegistration", testThatNewRegistrationWithSameArgumentsOverridesPreviousRegistration),
|
||||
]
|
||||
}
|
||||
|
||||
extension TypeForwardingTests {
|
||||
// DO NOT MODIFY: This is autogenerated, use:
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__TypeForwardingTests = [
|
||||
("testThatItCallsResolvedDependenciesBlockProvidedAfterRegistrationWhenResolvingByTypeForwarding", testThatItCallsResolvedDependenciesBlockProvidedAfterRegistrationWhenResolvingByTypeForwarding),
|
||||
("testThatItCallsResolvedDependenciesBlockWhenResolvingByTypeForwarding", testThatItCallsResolvedDependenciesBlockWhenResolvingByTypeForwarding),
|
||||
("testThatItCanResolveOptional", testThatItCanResolveOptional),
|
||||
("testThatItDoesNotOverrideIfDefinitionForwardsTheSameTypeWithDifferentTag", testThatItDoesNotOverrideIfDefinitionForwardsTheSameTypeWithDifferentTag),
|
||||
("testThatItDoesNotResolveByTypeForwardingIfRegisteredForAnotherTag", testThatItDoesNotResolveByTypeForwardingIfRegisteredForAnotherTag),
|
||||
("testThatItDoesNotReuseInstanceResolvedByTypeForwardingRegisteredForAnotherTag", testThatItDoesNotReuseInstanceResolvedByTypeForwardingRegisteredForAnotherTag),
|
||||
("testThatItFallbackToDefinitionWithNoTagWhenResolvingInstanceByTypeForwarding", testThatItFallbackToDefinitionWithNoTagWhenResolvingInstanceByTypeForwarding),
|
||||
("testThatItFirstUsesTaggedDefinitionWhenResolvingOptional", testThatItFirstUsesTaggedDefinitionWhenResolvingOptional),
|
||||
("testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType", testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType),
|
||||
("testThatItResolvesInstanceByTypeForwarding", testThatItResolvesInstanceByTypeForwarding),
|
||||
("testThatItReusesInstanceResolvedByTypeForwarding", testThatItReusesInstanceResolvedByTypeForwarding),
|
||||
("testThatItReusesInstancesResolvedForOptionalType", testThatItReusesInstancesResolvedForOptionalType),
|
||||
("testThatItThrowsErrorWhenResolvingNotImplementedTypeWithTypeForwarding", testThatItThrowsErrorWhenResolvingNotImplementedTypeWithTypeForwarding),
|
||||
]
|
||||
}
|
||||
|
||||
public func __allTests() -> [XCTestCaseEntry] {
|
||||
return [
|
||||
testCase(AutoInjectionTests.__allTests__AutoInjectionTests),
|
||||
testCase(AutoWiringTests.__allTests__AutoWiringTests),
|
||||
testCase(ComponentScopeTests.__allTests__ComponentScopeTests),
|
||||
testCase(ContextTests.__allTests__ContextTests),
|
||||
testCase(DefinitionTests.__allTests__DefinitionTests),
|
||||
testCase(DipTests.__allTests__DipTests),
|
||||
testCase(RuntimeArgumentsTests.__allTests__RuntimeArgumentsTests),
|
||||
testCase(TypeForwardingTests.__allTests__TypeForwardingTests),
|
||||
]
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user