Compare commits

...

40 Commits

Author SHA1 Message Date
Ilya Puchka 142a348b20 removed unneded builds from travis 2018-04-28 20:05:53 +01:00
Ilya Puchka 88f101639d updated travis config 2018-04-28 19:48:03 +01:00
Ilya Puchka 5e70633ece bumped swift version to 4.1 2018-04-28 19:43:49 +01:00
Ilya Puchka af57aa26ed bumped version to 6.1 2018-04-28 19:41:45 +01:00
Ilya Puchka 6d6d77d603 fixed swift 4.1 warnings 2018-04-28 19:39:46 +01:00
Ilya Puchka 8d2f6ab8fb Revert #171 (#189)
* Revert "fix merge conflict"

This reverts commit aff01c541b.

* Revert "Merge branch 'develop' into develop"

This reverts commit a8dd47cee5, reversing
changes made to 9e7bd51bcd.
2018-04-28 19:21:05 +01:00
Ilya Puchka 2cc5310d4b Merge pull request #182 from tapsandswipes/develop
Fix crash with colaborator containers and weak singletons
2018-02-26 13:25:17 +00:00
Antonio Cabezuelo Vivo 5cb03a11bb Fix crash with colaborator containers and weak singletons
Signed-off-by: Antonio Cabezuelo Vivo <antonio@tapsandswipes.com>
2018-02-12 14:17:31 +01:00
Ilya Puchka aff01c541b fix merge conflict 2017-12-12 16:56:23 +01:00
Ilya Puchka a8dd47cee5 Merge branch 'develop' into develop 2017-12-12 16:51:32 +01:00
Ilya Puchka 12738a665f Merge pull request #171 from creditkarma/parent_child_containers
Parent child container support for Dip
2017-12-12 16:33:32 +01:00
Oleksa 'trimm' Korin 9e7bd51bcd Restructured tests, fixed crash 2017-10-30 23:49:44 +02:00
Oleksa 'trimm' Korin ce394e7d2b Added reproduction test 2017-10-30 23:26:36 +02:00
Oleksa 'trimm' Korin cd2c66f4a8 Initial try for collaboration reproduction crash 2017-10-30 20:45:51 +02:00
Ilya Puchka 5464f00bad Merge pull request #177 from AliSoftware/release/6.0
Release 6.0
2017-10-09 18:12:39 +02:00
Ilya Puchka 5b9cc50190 Merge branch 'master' into release/6.0 2017-09-27 00:35:49 +02:00
Ilya Puchka a7c8616300 updated changelog 2017-09-27 00:34:57 +02:00
Ilya Puchka 8349fbd8d8 bump version to 6.0 2017-09-26 23:51:08 +02:00
Ilya Puchka 4b1ecbcb8e removed previously deprecated method 2017-09-26 23:50:56 +02:00
Ilya Puchka 2f0e1fdb10 Merge pull request #176 from AliSoftware/swift4
Swift 4 migration
2017-09-26 23:45:25 +02:00
Ilya Puchka 4a8a1daeca swift version settings update 2017-09-21 22:26:19 +02:00
Ilya Puchka 56554147cb travis update 2017-09-16 19:36:07 +02:00
Ilya Puchka a554454afe fixed failing tests 2017-09-16 19:24:15 +02:00
Ilya Puchka dde2e98953 project settings updated and warnings fixed 2017-09-16 18:52:58 +02:00
Ilya Puchka a2c04ed61e migrate tests 2017-09-16 18:39:12 +02:00
Ilya Puchka c64cf720b8 swift 4 migration 2017-09-16 18:04:36 +02:00
John Twigg 3429c6ae0b Parent child container support for Dip 2017-08-02 10:41:03 -07:00
Ilya Puchka 451fb03bc8 updated changelog 2017-07-30 12:31:06 +02:00
Ilya Puchka b1ad2a65b2 Merge pull request #169 from AliSoftware/fix-collaboration-sharing-singletons
Fix: containers with common collaborator share resolved instances for their own definitions
2017-07-30 12:19:34 +02:00
Ilya Puchka 3f8b83b87c addet test for peforming autowiring before collaboration 2017-07-29 18:16:54 +02:00
Ilya Puchka b7bf4904e9 fixed sharing singletons during collaboration 2017-07-29 18:04:28 +02:00
Ilya Puchka 199b1aec8f Merge pull request #156 from kandelvijaya/improvement/equatableIntoItsExtension
Added Equatable conformance on the site of declaration
2017-04-14 23:06:30 +02:00
Ilya Puchka 22d19697f1 Merge pull request #155 from kandelvijaya/patch-1
Playgrounds typo fixes
2017-04-14 23:05:22 +02:00
vkandel d809177273 moved equatable conformance into Hashable declaration site for DefinationKey 2017-04-09 21:41:10 +02:00
vkandel 420c866726 Added Equatable conformance on the site of declaration 2017-04-09 21:32:31 +02:00
Vijaya Prakash Kandel 6e6cc0b1df Merge pull request #1 from kandelvijaya/patch-2
Update Contents.swift
2017-04-09 21:04:19 +02:00
Vijaya Prakash Kandel b71f50cef5 Update Contents.swift 2017-04-09 21:03:56 +02:00
Vijaya Prakash Kandel 462d528474 Update Contents.swift 2017-04-09 21:02:00 +02:00
Ilya Puchka 01c318bd5c Merge branch 'release/5.1' into develop 2017-04-09 13:20:40 +02:00
Ilya Puchka a0c890c931 Merge pull request #152 from AliSoftware/release/5.1
Release 5.1
2017-04-09 13:18:56 +02:00
33 changed files with 423 additions and 343 deletions
+1 -1
View File
@@ -1 +1 @@
3.1
4.1
+6 -22
View File
@@ -3,21 +3,17 @@ 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
- carthage build --no-skip-current
os: osx
osx_image: xcode8.3
osx_image: xcode9.3
language: objective-c
before_install:
- gem install cocoapods --version 1.1.0.rc.2 --no-document
- script:
- swift build --clean && swift build && swift test
- swift package clean && swift build && swift test
os: linux
dist: trusty
sudo: required
@@ -25,25 +21,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-4.1-RELEASE
- wget https://swift.org/builds/swift-4.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
os: linux
dist: trusty
sudo: required
language: generic
before_install:
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
- cd ..
- export SWIFT_VERSION=swift-3.1-RELEASE
- wget https://swift.org/builds/swift-3.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
- swift package clean && swift build && swift test
notifications:
email: false
+14
View File
@@ -1,5 +1,19 @@
# CHANGELOG
## 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.
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Dip"
s.version = "5.1"
s.version = "6.1"
s.summary = "Dependency Injection for Swift made easy."
s.description = <<-DESC
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
+21 -5
View File
@@ -208,7 +208,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0800;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = AliSoftware;
TargetAttributes = {
0903B3571C161543002241C1 = {
@@ -386,20 +386,28 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 5.1;
CURRENT_PROJECT_VERSION = 6.1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -424,7 +432,7 @@
ONLY_ACTIVE_ARCH = YES;
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0.2;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
VERSIONING_SYSTEM = "apple-generic";
@@ -441,20 +449,28 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 5.1;
CURRENT_PROJECT_VERSION = 6.1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -472,7 +488,7 @@
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 = 4.0;
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
VALIDATE_PRODUCT = YES;
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -40,8 +40,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 -1
View File
@@ -9,7 +9,7 @@
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<string>6.1</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
+1 -1
View File
@@ -9,7 +9,7 @@
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<string>6.1</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
Binary file not shown.
Binary file not shown.
+1 -175
View File
@@ -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.
@@ -279,7 +279,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0800;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = AliSoftware;
TargetAttributes = {
0990225E1BC123C000E76F43 = {
@@ -427,13 +427,23 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -461,7 +471,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 4.0;
};
name = Debug;
};
@@ -473,13 +483,23 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -498,7 +518,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 4.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -40,8 +40,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
@@ -1,5 +1,15 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
@@ -31,6 +41,16 @@
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
@@ -62,6 +82,16 @@
"idiom" : "ipad",
"filename" : "Icon-152.png",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
+1 -1
View File
@@ -9,7 +9,7 @@
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<string>6.1</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)
}
+1 -1
View File
@@ -9,7 +9,7 @@
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<string>6.1</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
+2 -2
View File
@@ -256,7 +256,7 @@ public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropert
}
class _InjectedPropertyBox<T> {
public class _InjectedPropertyBox<T> {
let required: Bool
let didInject: (T) -> ()
@@ -275,7 +275,7 @@ class _InjectedPropertyBox<T> {
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)
+10 -10
View File
@@ -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?
@@ -47,15 +47,15 @@ public struct DefinitionKey : Hashable, CustomStringConvertible {
tagged.tag = tag
return tagged
}
}
/// Check two definition keys on equality by comparing their `type`, `factoryType` and `tag` properties.
public func ==(lhs: DefinitionKey, rhs: DefinitionKey) -> Bool {
return
lhs.type == rhs.type &&
/// Check two definition keys on equality by comparing their `type`, `factoryType` and `tag` properties.
public static func ==(lhs: DefinitionKey, rhs: DefinitionKey) -> Bool {
return
lhs.type == rhs.type &&
lhs.typeOfArguments == rhs.typeOfArguments &&
lhs.tag == rhs.tag
}
}
///Dummy protocol to store definitions for different types in collection
@@ -198,7 +198,7 @@ public final class Definition<T, U>: DefinitionType {
//MARK: - _Definition
protocol _Definition: DefinitionType, AutoWiringDefinition, TypeForwardingDefinition {
protocol _Definition: AutoWiringDefinition, TypeForwardingDefinition {
var type: Any.Type { get }
var scope: ComponentScope { get }
var weakFactory: ((Any) throws -> Any)! { get }
@@ -208,8 +208,8 @@ protocol _Definition: DefinitionType, AutoWiringDefinition, TypeForwardingDefini
//MARK: - Type Forwarding
protocol _TypeForwardingDefinition: TypeForwardingDefinition, _Definition {
weak var forwardsTo: _TypeForwardingDefinition? { get }
protocol _TypeForwardingDefinition: _Definition {
var forwardsTo: _TypeForwardingDefinition? { get }
var forwardsFrom: [_TypeForwardingDefinition] { get set }
func _implements(type aType: Any.Type)
func _implements(types aTypes: [Any.Type])
+48 -20
View File
@@ -34,7 +34,7 @@ public final class DependencyContainer {
- seealso: `DependencyTagConvertible`
*/
public enum Tag: Equatable {
public enum Tag {
case String(StringLiteralType)
case Int(IntegerLiteralType)
}
@@ -50,7 +50,7 @@ public final class DependencyContainer {
private var _weakCollaborators: [WeakBox<DependencyContainer>] = []
var _collaborators: [DependencyContainer] {
get {
return _weakCollaborators.flatMap({ $0.value })
return _weakCollaborators.compactMap({ $0.value })
}
set {
_weakCollaborators = newValue.filter({ $0 !== self }).map(WeakBox.init)
@@ -167,12 +167,15 @@ extension DependencyContainer {
/// The label of the property where resolved instance will be auto-injected.
private(set) public var injectedInProperty: String?
let inCollaboration: Bool
var logErrors: Bool = true
init(key: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String?) {
init(key: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String?, inCollaboration: Bool) {
self.key = key
self.injectedInType = injectedInType
self.injectedInProperty = injectedInProperty
self.inCollaboration = inCollaboration
}
public var debugDescription: String {
@@ -196,7 +199,7 @@ extension DependencyContainer {
/// Pushes new context created with provided values and calls block. When block returns previous context is restored.
/// When popped to initial (root) context will release all references to resolved instances and call `Resolvable` callbacks.
func inContext<T>(key aKey: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String? = nil, logErrors: Bool! = nil, block: () throws -> T) rethrows -> T {
func inContext<T>(key aKey: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String? = nil, inCollaboration: Bool = false, container: DependencyContainer? = nil, logErrors: Bool! = nil, block: () throws -> T) rethrows -> T {
let key = aKey
return try threadSafe {
let currentContext = self.context
@@ -207,6 +210,10 @@ extension DependencyContainer {
//clean instances pool if it is owned not by other container
if context == nil {
resolvedInstances.resolvedInstances.removeAll()
for (key, instance) in resolvedInstances.sharedWeakSingletons {
if resolvedInstances.sharedWeakSingletons[key] is WeakBoxType { continue }
resolvedInstances.sharedWeakSingletons[key] = WeakBox(instance)
}
for (key, instance) in resolvedInstances.weakSingletons {
if resolvedInstances.weakSingletons[key] is WeakBoxType { continue }
resolvedInstances.weakSingletons[key] = WeakBox(instance)
@@ -222,7 +229,8 @@ extension DependencyContainer {
context = Context(
key: key,
injectedInType: injectedInType,
injectedInProperty: injectedInProperty
injectedInProperty: injectedInProperty,
inCollaboration: inCollaboration
)
context.logErrors = logErrors ?? currentContext?.logErrors ?? true
@@ -258,17 +266,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 +299,23 @@ extension DependencyContainer {
let context = collaborator.context
collaborator.context = self.context
defer {
collaborator.resolvedInstances = resolvedInstances
collaborator.context = context
collaborator.resolvedInstances = resolvedInstances
for (key, resolvedSingleton) in self.resolvedInstances.singletons {
collaborator.resolvedInstances.singletons[key] = resolvedSingleton
}
for (key, resolvedSingleton) in self.resolvedInstances.weakSingletons {
guard collaborator.definition(matching: key) == nil else { continue }
collaborator.resolvedInstances.weakSingletons[key] = resolvedSingleton is WeakBoxType ? resolvedSingleton : WeakBox(resolvedSingleton)
}
for (key, resolved) in self.resolvedInstances.resolvedInstances {
guard collaborator.definition(matching: key) == nil else { continue }
collaborator.resolvedInstances.resolvedInstances[key] = resolved
}
}
let resolved = try collaborator.inContext(key:key, injectedInType: self.context.injectedInType, injectedInProperty: self.context.injectedInProperty, logErrors: false) {
let resolved = try collaborator.inContext(key:key, injectedInType: self.context.injectedInType, injectedInProperty: self.context.injectedInProperty, inCollaboration: true, logErrors: false) {
try collaborator._resolve(key: key, builder: builder)
}
@@ -336,6 +356,8 @@ extension DependencyContainer {
definitions[key] = nil
resolvedInstances.singletons[key] = nil
resolvedInstances.weakSingletons[key] = nil
resolvedInstances.sharedSingletons[key] = nil
resolvedInstances.sharedWeakSingletons[key] = nil
}
}
@@ -348,6 +370,8 @@ extension DependencyContainer {
definitions.removeAll()
resolvedInstances.singletons.removeAll()
resolvedInstances.weakSingletons.removeAll()
resolvedInstances.sharedSingletons.removeAll()
resolvedInstances.sharedWeakSingletons.removeAll()
bootstrapped = false
}
}
@@ -477,13 +501,17 @@ extension DependencyContainer.Tag: ExpressibleByIntegerLiteral {
}
public func ==(lhs: DependencyContainer.Tag, rhs: DependencyContainer.Tag) -> Bool {
switch (lhs, rhs) {
case let (.String(lhsString), .String(rhsString)):
return lhsString == rhsString
case let (.Int(lhsInt), .Int(rhsInt)):
return lhsInt == rhsInt
default:
return false
extension DependencyContainer.Tag: Equatable {
public static func ==(lhs: DependencyContainer.Tag, rhs: DependencyContainer.Tag) -> Bool {
switch (lhs, rhs) {
case let (.String(lhsString), .String(rhsString)):
return lhsString == rhsString
case let (.Int(lhsInt), .Int(rhsInt)):
return lhsInt == rhsInt
default:
return false
}
}
}
+2
View File
@@ -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 })
+74 -32
View File
@@ -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
@@ -175,7 +211,7 @@ extension DependencyContainer {
return previouslyResolved
}
resolvedInstances[key: key, inScope: definition.scope] = resolvedInstance
resolvedInstances[key: key, inScope: definition.scope, context: context] = resolvedInstance
if let resolvable = resolvedInstance as? Resolvable {
resolvedInstances.resolvableInstances.append(resolvable)
@@ -191,7 +227,7 @@ extension DependencyContainer {
private func previouslyResolved<T>(for definition: _Definition, key: DefinitionKey) -> T? {
//first check if exact key was already resolved
if let previouslyResolved = resolvedInstances[key: key, inScope: definition.scope] as? T {
if let previouslyResolved = resolvedInstances[key: key, inScope: definition.scope, context: context] as? T {
return previouslyResolved
}
//then check if any related type was already resolved
@@ -199,7 +235,7 @@ extension DependencyContainer {
DefinitionKey(type: $0, typeOfArguments: key.typeOfArguments, tag: key.tag)
})
for key in keys {
if let previouslyResolved = resolvedInstances[key: key, inScope: definition.scope] as? T {
if let previouslyResolved = resolvedInstances[key: key, inScope: definition.scope, context: context] as? T {
return previouslyResolved
}
}
@@ -207,7 +243,7 @@ extension DependencyContainer {
}
/// Searches for definition that matches provided key
private func definition(matching key: DefinitionKey) -> KeyDefinitionPair? {
func definition(matching key: DefinitionKey) -> KeyDefinitionPair? {
if let definition = (self.definitions[key] ?? self.definitions[key.tagged(with: nil)]) {
return (key, definition)
}
@@ -230,41 +266,47 @@ 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(key key: DefinitionKey, inScope scope: ComponentScope, context context: DependencyContainer.Context) -> Any? {
get {
if scope == .singleton || scope == .eagerSingleton {
return singletons[key]
}
if scope == .weakSingleton {
if let boxed = weakSingletons[key] as? WeakBoxType { return boxed.unboxed }
else { return weakSingletons[key] }
}
if scope == .shared {
switch scope {
case .singleton, .eagerSingleton:
return context.inCollaboration ? sharedSingletons[key] : singletons[key]
case .weakSingleton:
let singletons = context.inCollaboration ? sharedWeakSingletons : weakSingletons
if let boxed = singletons[key] as? WeakBoxType { return boxed.unboxed }
else { return singletons[key] }
case .shared:
return resolvedInstances[key]
case .unique:
return nil
}
return nil
}
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
}
}
}
+18 -17
View File
@@ -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:)`
-6
View File
@@ -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)
+4 -4
View File
@@ -112,7 +112,7 @@ class AutoWiringTests: XCTestCase {
//2 args
var factoryWithMostNumberOfArgumentsCalled = false
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolvingProperties { _ in
.resolvingProperties { _,_ in
factoryWithMostNumberOfArgumentsCalled = true
}
@@ -164,7 +164,7 @@ class AutoWiringTests: XCTestCase {
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
//2 arg tagged
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }.resolvingProperties { _ in
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }.resolvingProperties { _,_ in
taggedFactoryWithMostNumberOfArgumentsCalled = true
}
@@ -189,7 +189,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 +208,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
}
+15 -15
View File
@@ -63,7 +63,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
}
@@ -71,7 +71,7 @@ class ContextTests: XCTestCase {
container.register { () -> ServiceImp1 in
XCTAssertTrue(self.container.context.resolvingType == ServiceImp1.self)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertTrue(self.container.context.resolvingType == ServiceImp1.self)
}
@@ -83,7 +83,7 @@ class ContextTests: XCTestCase {
XCTAssertNil(self.container.context.injectedInType)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNil(self.container.context.injectedInType)
let _ = try self.container.resolve() as ServiceImp1
}
@@ -91,7 +91,7 @@ class ContextTests: XCTestCase {
container.register { () -> ServiceImp1 in
XCTAssertTrue(self.container.context.injectedInType == Service.self)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertTrue(self.container.context.injectedInType == Service.self)
}
@@ -104,7 +104,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve(tag: "otherTag") as ServiceImp1
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve(tag: "otherTag") as ServiceImp1
@@ -114,7 +114,7 @@ class ContextTests: XCTestCase {
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("otherTag") ~= self.container.context.tag!)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("otherTag") ~= self.container.context.tag!)
}
@@ -135,7 +135,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(DependencyContainer.Tag.String("injectedTag") ~= self.container.context.tag!)
}
return ServiceImp2()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
if self.container.context.injectedInProperty == "injectedNilTag" {
XCTAssertNil(self.container.context.tag)
}
@@ -149,7 +149,7 @@ class ContextTests: XCTestCase {
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
return ServiceImp2()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
}
@@ -160,14 +160,14 @@ class ContextTests: XCTestCase {
func testThatContextStoresTheTagPassedToResolveWhenAutoWiring() {
container.register { (_: ServiceImp1) -> Service in
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
}
container.register { () -> ServiceImp1 in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
}
@@ -181,7 +181,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve() as ServiceImp1
@@ -190,7 +190,7 @@ class ContextTests: XCTestCase {
container.register { () -> ServiceImp1 in
XCTAssertNil(self.container.context.tag)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNil(self.container.context.tag)
}
@@ -207,7 +207,7 @@ class ContextTests: XCTestCase {
XCTAssertNotNil(self.container.context.injectedInProperty)
XCTAssertTrue(names.contains(self.container.context.injectedInProperty!))
return ServiceImp2()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.injectedInProperty)
XCTAssertTrue(names.contains(self.container.context.injectedInProperty!))
}
@@ -239,7 +239,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
}
@@ -247,7 +247,7 @@ class ContextTests: XCTestCase {
collaborator.register { () -> ServiceImp1 in
XCTAssertTrue(collaborator.context.resolvingType == ServiceImp1.self)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertTrue(collaborator.context.resolvingType == ServiceImp1.self)
}
+122 -7
View File
@@ -70,6 +70,7 @@ class DipTests: XCTestCase {
("testThatCollaboratingWithSelfIsIgnored", testThatCollaboratingWithSelfIsIgnored),
("testThatCollaboratingContainersAreWeakReferences", testThatCollaboratingContainersAreWeakReferences),
("testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer", testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer),
("testThatItCanHandleSeparateContainersAndTheirCollaboration", testThatItCanHandleSeparateContainersAndTheirCollaboration)
]
}()
@@ -573,12 +574,12 @@ class DipTests: XCTestCase {
}.implements(Service.self)
container.register(tag: "tag") { ServiceImp2() as Service }
.resolvingProperties { _ in
.resolvingProperties { _,_ in
createdService2 = true
}
container.register { (arg: String) in ServiceImp1() }
.resolvingProperties { _ in
.resolvingProperties { _,_ in
createdService3 = true
}
@@ -743,16 +744,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 +761,124 @@ 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
)
}
}
+4 -4
View File
@@ -154,9 +154,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 +184,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
}