Compare commits

..

130 Commits

Author SHA1 Message Date
Ilya Puchka c3b601df0f Merge pull request #235 from AliSoftware/develop
Release 7.1.1
2019-12-27 11:36:42 +00:00
Ilya Puchka 56b0768d60 bump version to 7.1.1 2019-12-27 11:14:55 +00:00
Ilya Puchka 8cf87efb95 Update podspec author 2019-12-27 11:07:21 +00:00
Ilya Puchka 3aa9b334f1 Merge pull request #233 from AliSoftware/spm-fix
Enabled StoryboardInstantiatable for SPM builds
2019-11-15 11:53:25 +00:00
Ilya Puchka b2a0cda242 Update StoryboardInstantiatable.swift 2019-11-13 13:16:52 +00:00
Ilya Puchka 07eb66e87d Merge pull request #231 from AliSoftware/develop
Release 7.1.0
2019-11-11 14:41:08 +00:00
Ilya Puchka 82e3d02497 Merge branch 'master' into develop 2019-11-11 14:22:24 +00:00
Ilya Puchka 3b2f5a272f bumpe version to 7.1.0 2019-11-10 16:11:17 +00:00
Ilya Puchka eab2d424e7 allow to disable thread safety on container level 2019-11-10 16:01:20 +00:00
Ilya Puchka 0f2cda0a52 update changelog 2019-11-10 15:53:45 +00:00
Ilya Puchka 05c02c9645 Merge pull request #225 from AliSoftware/property-delegates
Property wrappers
2019-11-10 15:52:49 +00:00
Ilya Puchka fa086dad8f add xcode 11 and swift 5.1 to travis build 2019-11-10 15:35:53 +00:00
Ilya Puchka cdc09f5a03 removed unneeded initial nil values 2019-11-10 15:22:38 +00:00
Ilya Puchka b94ed3bea2 fix warning 2019-11-10 15:22:16 +00:00
Ilya Puchka 0fd70e65dd Merge branch 'develop' into property-delegates 2019-11-10 15:13:55 +00:00
Ilya Puchka 97e7f4782f Merge branch 'pr/221' into develop 2019-11-10 15:12:41 +00:00
Ilya Puchka f1fdbbc988 code review 2019-11-10 15:02:03 +00:00
Ilya Puchka e368bb3051 Merge branch 'develop' into nested_types 2019-11-10 14:50:07 +00:00
Ilya Puchka 4ce4832960 Merge pull request #229 from dchohfi/develop
Bump watchos deployment target to 3.0
2019-10-28 08:46:22 +00:00
Diego Chohfi d3bd0c27e3 Bump watchos deployment target to 3.0 2019-10-21 10:40:46 -07:00
Ilya Puchka be0c39ab6b update for beta 3 2019-07-07 23:54:58 +01:00
Ilya Puchka 0de45e7d53 fixed checking for new injected value 2019-07-07 23:53:45 +01:00
Ilya Puchka 3b421d0cff refactor property wrappers to struct 2019-07-07 16:16:50 +01:00
Ilya Puchka f1234bf2b9 introduce swift 5.1 property delegates 2019-06-30 19:12:42 +01:00
Ilya Puchka b0d7153bfe ignore swiftpm files 2019-06-30 18:27:59 +01:00
Ilya Puchka 0193aa6bf6 Merge pull request #224 from AliSoftware/swift5
Swift 5
2019-06-30 17:17:49 +01:00
Ilya Puchka de7ad3ac48 removed linux thread safety tests, regenerate test manifest 2019-06-30 16:59:10 +01:00
Ilya Puchka 40ad490c48 removed unneeded code 2019-06-30 15:53:23 +01:00
Ilya Puchka 95cc5df26f fixed Linux tests 2019-06-30 15:40:40 +01:00
Ilya Puchka 09a7115aff fix tests 2019-06-30 14:29:22 +01:00
Ilya Puchka 15c0002ea3 remove compatibility file 2019-06-12 01:18:14 +01:00
Ilya Puchka 0644d85a9c update swift version in all targets 2019-06-12 01:18:05 +01:00
Ilya Puchka e1522a0bf3 Merge branch 'develop' into swift5 2019-06-12 01:15:06 +01:00
Ilya Puchka a659415496 generate LinuxMain 2019-06-11 23:23:39 +01:00
Ilya Puchka efe25d575b update package description 2019-06-11 23:10:22 +01:00
Ilya Puchka 22c67fa30c disable spec validation 2019-06-11 21:30:55 +01:00
Ilya Puchka 7a091da44d migrate to swift 5 2019-06-11 21:16:03 +01:00
s 9580976dd8 Print nested types in errors, hash keys using full typenames 2019-04-01 17:13:06 +02:00
Ilya Puchka a4f0256313 fixed typos 2018-12-20 01:32:21 +00:00
Ilya Puchka 815e9ccd66 shorthand method for resolving properties via keypaths 2018-12-20 01:30:35 +00:00
Ilya Puchka b9bf9c4d75 Merge pull request #216 from AliSoftware/develop
Release 7.0.1
2018-12-19 22:54:14 +00:00
Ilya Puchka 530a20999a use Cocoapods 1.4.0 as latest versions fail validation 2018-12-19 15:56:32 +00:00
Ilya Puchka 4f3bc1e498 Merge branch 'master' into release/7.0.1 2018-11-19 20:35:40 +00:00
Ilya Puchka 8dcb136ff0 fixed typos 2018-11-19 20:34:56 +00:00
Ilya Puchka 88d02af706 bump version to 7.0.1 2018-11-19 20:32:40 +00:00
Ilya Puchka a8777c067e Allow to disabled/enable auto injection for container or single definition. fixes #214, resolves #212 2018-11-19 00:03:15 +00:00
Ilya Puchka db40e8580c Added test for regression SR-8878 2018-11-19 00:03:15 +00:00
Ilya Puchka 334fb384a5 Update README.md 2018-11-18 23:54:49 +00:00
Ilya Puchka 54e1db2232 Merge pull request #207 from AliSoftware/develop
Release 7.0.0
2018-09-22 23:31:41 +03:00
Ilya Puchka c5c6bd2821 Merge branch 'master' into develop 2018-09-22 23:20:46 +03:00
Ilya Puchka 593129c63e update cocoapods on travis 2018-09-22 20:47:45 +01:00
Ilya Puchka 9a8d919a13 bump xcode and swift version on travis 2018-09-22 20:16:49 +01:00
Ilya Puchka 17a2d64361 bumped version to 7.0.0 2018-09-22 20:16:49 +01:00
Ilya Puchka 27037c2dd7 fix indentation in some docs 2018-09-22 20:01:16 +01:00
Ilya Puchka bd253f4b0a bump xcode and swift version on travis 2018-09-22 19:48:10 +01:00
Ilya Puchka 882b2a2031 bumped version to 7.0 2018-09-22 19:25:18 +01:00
Ilya Puchka 6a14c1f96d updated CHANGELOG 2018-09-22 19:24:00 +01:00
Ilya Puchka f60e322445 bumped swift version, removed unneded IUO tests 2018-09-22 19:19:45 +01:00
Ilya Puchka 77f6fde2fa Merge branch 'swift42' into develop 2018-09-22 19:16:27 +01:00
Ilya Puchka a8f7a2972a silence warning 2018-09-22 19:15:43 +01:00
Ilya Puchka ce9088afc7 fix reusing optionals 2018-09-22 18:47:34 +01:00
Ilya Puchka ef563c65ba fix build error on mac with SPM 2018-09-19 16:46:31 +03:00
Ilya Puchka 90ff39c720 fix build error on mac with SPM 2018-09-19 15:13:22 +03:00
Ilya Puchka e45dbd634f Merge with DipUI (#206)
* merge with DipUI
2018-09-19 15:02:26 +03:00
Bruno Virlet f81c267c61 Disable gathering code coverage (#198)
This causes issues whenn linking as a static library using Carthage
2018-07-25 18:10:51 +01:00
Michele Gruppioni d5b07b1916 Removed extension of ImplicitlyUnwrappedOptional (#191)
* Removed extension of ImplicitlyUnwrappedOptional

It was deprecated and has been removed in swift 4.2

* Added Swift Version Check
2018-07-13 11:43:40 +01:00
Ilya Puchka 33993df68a disable test coverage 2018-06-06 21:08:44 +01:00
Ilya Puchka dadb68862a fixed getting resolved instances 2018-06-06 01:15:08 +01:00
Ilya Puchka 2e53aa8ae2 Merge pull request #190 from AliSoftware/develop
Release 6.1
2018-04-28 20:24:35 +01:00
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
Ilya Puchka 9b2a7918d8 Merge pull request #154 from AliSoftware/auto-wiring-tag-fix
Fixed auto-wiring with tagged definitions
2017-04-09 13:08:04 +02:00
Ilya Puchka 218b5a4e9a disable running tests on watchos on Travis
https://github.com/travis-ci/travis-ci/issues/7580
2017-04-09 12:56:22 +02:00
Ilya Puchka 0b221f3368 fixed auto-wiring with tagged definitions 2017-04-09 12:08:48 +02:00
Ilya Puchka 3b943c10ef Merge branch 'master' into release/5.1 2017-04-06 22:51:21 +02:00
Ilya Puchka a1da60bd14 updated CHANGELOG, bumped version to 5.1 2017-04-06 22:49:05 +02:00
Ilya Puchka 1825cd7d4c Merge pull request #151 from AliSoftware/recursive-collaboration
Fixed collaboration shared references
2017-04-06 22:40:08 +02:00
Ilya Puchka e7d8fb41e1 fixed collaboration references, now collaboration is bidirectional 2017-04-06 21:46:08 +02:00
Ilya Puchka 1c398defeb Merge pull request #150 from AliSoftware/drop-swift2.3
Drop Swift 2.3
2017-04-06 10:49:51 +02:00
Ilya Puchka ab561546f0 allow spec warnings 2017-04-06 00:43:48 +02:00
Ilya Puchka c0fb925ab8 updated travis config to build for 3.0 and 3.1 on Linux 2017-04-06 00:00:22 +02:00
Ilya Puchka 80ee4865ce drop swift 2.3 support 2017-04-01 00:44:10 +02:00
Ilya Puchka d95df1343e minor changes for loging function 2017-03-30 19:43:11 +02:00
Ilya Puchka a83d866cbd Merge pull request #146 from Pr0Ger/develop
Enable use of custom or no logging function
2017-03-30 19:42:25 +02:00
Ilya Puchka cc1dcba4b9 Merge pull request #145 from DenHeadless/patch-1
Fix swift 3.1 warning
2017-03-30 19:15:19 +02:00
Sergey Petrov 0ceb6a3503 Enable use of custom or no logging function 2017-03-30 17:02:11 +03:00
Denys Telezhkin 4e641a6465 fix swift 3.1 warning 2017-03-30 15:14:27 +03:00
Ilya Puchka 35b6da8556 fixed method name inconsistency 2017-03-10 00:01:37 +01:00
Ilya Puchka 47bc1913e3 Merge pull request #141 from AliSoftware/swift-3.0.2
Swift 3.0.2
2017-01-23 23:24:02 +01:00
Ilya Puchka 24d341503e swift 3.0.2 2017-01-21 23:04:50 +01:00
Ilya Puchka 3c1331089b Merge branch 'hotfix/swift2.3-api-diff' into develop 2016-11-01 17:24:21 +03:00
Ilya Puchka 5eb0eece56 Merge branch 'release/5.0.3' into develop 2016-10-23 23:54:58 +03:00
75 changed files with 2733 additions and 3288 deletions
+1
View File
@@ -36,3 +36,4 @@ Carthage
# SPM
.build/
Packages
.swiftpm
-1
View File
@@ -1 +0,0 @@
3.0
+22 -18
View File
@@ -5,18 +5,27 @@ matrix:
- script:
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk macosx -destination 'platform=macOS,arch=x86_64' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV 1080p,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild -workspace Dip.xcworkspace -scheme Dip -sdk watchsimulator -destination 'platform=watchOS Simulator,name=Apple Watch - 38mm,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty - c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme DipSampleApp -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- pod spec lint
# - pod spec lint --allow-warnings
- carthage build --no-skip-current
- swift package clean && swift build && swift test
os: osx
osx_image: xcode8
osx_image: xcode10.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
@@ -24,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 package clean && swift build && swift test
os: linux
dist: trusty
sudo: required
@@ -38,16 +47,11 @@ matrix:
before_install:
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
- cd ..
- export SWIFT_VERSION=swift-DEVELOPMENT-SNAPSHOT-2016-09-07-a
- wget https://swift.org/builds/development/ubuntu1404/$SWIFT_VERSION/$SWIFT_VERSION-ubuntu14.04.tar.gz
- 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}"
- export SWIFT_RELEASE_VERSION=2.2.1
- export SWIFT_RELEASE_NAME="${SWIFT_RELEASE_VERSION}-RELEASE"
- wget https://swift.org/builds/swift-$SWIFT_RELEASE_VERSION-release/ubuntu1404/swift-$SWIFT_RELEASE_NAME/swift-$SWIFT_RELEASE_NAME-ubuntu14.04.tar.gz
- tar xzf swift-$SWIFT_RELEASE_NAME-ubuntu14.04.tar.gz
- export SWIFT_EXEC="${PWD}/swift-${SWIFT_RELEASE_NAME}-ubuntu14.04/usr/bin/swiftc"
- cd Dip
- cd Dip
notifications:
email: false
+56 -1
View File
@@ -1,10 +1,65 @@
# CHANGELOG
## Develop
## 7.1.1
* Fixed using `StoryboardInstantiatable` with SPM ([#233](https://github.com/AliSoftware/Dip/pull/233)).
## 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.
[#150](https://github.com/AliSoftware/Dip/issues/150), [@ilyapuchka](https://github.com/ilyapuchka)
* Added custom logging function.
[#146](https://github.com/AliSoftware/Dip/issues/146), [@Pr0Ger](https://github.com/Pr0Ger)
#### Fixed
* Fixed Swift 3.1 warnings.
[#145](https://github.com/AliSoftware/Dip/issues/145), [@DenHeadless](https://github.com/DenHeadless)
* Fixed collaboration shared references.
[#151](https://github.com/AliSoftware/Dip/issues/151), [@ilyapuchka](https://github.com/ilyapuchka)
* Fixed autowiring when using tags.
[#154](https://github.com/AliSoftware/Dip/issues/154), [@ilyapuchka](https://github.com/ilyapuchka)
## 5.0.4
#### Fixed
* Fixed broken compatibility for Swift 2.3 API in `resolve(tag:arguments:)` method.
* Fixed broken compatibility for Swift 2.3 API in `resolve(tag:arguments:)` method.
[#135](https://github.com/AliSoftware/Dip/issues/135), [@ilyapuchka](https://github.com/ilyapuchka)
## 5.0.3
+4 -2
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Dip"
s.version = "5.0.4"
s.version = "7.1.1"
s.summary = "Dependency Injection for Swift made easy."
s.description = <<-DESC
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
s.homepage = "https://github.com/AliSoftware/Dip"
s.license = 'MIT'
s.authors = { "Olivier Halligon" => "olivier@halligon.net", "Ilya Puchka" => "ilya@puchka.me" }
s.authors = { "Olivier Halligon" => "olivier@halligon.net", "Ilya Puchka" => "ilyapuchka@gmail.com" }
s.source = { :git => "https://github.com/AliSoftware/Dip.git", :tag => s.version.to_s }
s.social_media_url = 'https://twitter.com/aligatr'
@@ -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>
+74 -38
View File
@@ -27,17 +27,12 @@
09BD35151D84E30D00B33E53 /* ThreadSafetyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD350B1D84E30D00B33E53 /* ThreadSafetyTests.swift */; };
09BD35161D84E30D00B33E53 /* TypeForwardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD350C1D84E30D00B33E53 /* TypeForwardingTests.swift */; };
09BD35171D84E30D00B33E53 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BD350D1D84E30D00B33E53 /* Utils.swift */; };
09FC48061DAA9AC700566AA8 /* Resolve_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48041DAA9AC700566AA8 /* Resolve_swift2.swift */; };
09FC48071DAA9AC700566AA8 /* Resolve.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48051DAA9AC700566AA8 /* Resolve.swift */; };
09FC480F1DAA9CAF00566AA8 /* Register.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC480C1DAA9CAF00566AA8 /* Register.swift */; };
09FC48101DAA9CAF00566AA8 /* Register_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC480D1DAA9CAF00566AA8 /* Register_swift2.swift */; };
09FC48141DAA9E0200566AA8 /* AutoInjection_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48121DAA9E0200566AA8 /* AutoInjection_swift2.swift */; };
09FC48181DAAA53100566AA8 /* DipError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48161DAAA53100566AA8 /* DipError.swift */; };
09FC48191DAAA53100566AA8 /* DipError_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48171DAAA53100566AA8 /* DipError_swift2.swift */; };
09FC481B1DAAA82800566AA8 /* RuntimeArguments_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC481A1DAAA82800566AA8 /* RuntimeArguments_swift2.swift */; };
09FC481E1DAAA8F900566AA8 /* ComponentScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC481C1DAAA8F900566AA8 /* ComponentScope.swift */; };
09FC481F1DAAA8F900566AA8 /* ComponentScope_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC481D1DAAA8F900566AA8 /* ComponentScope_swift2.swift */; };
09FC48211DAAAC4700566AA8 /* TypeForwarding_swift2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48201DAAAC4700566AA8 /* TypeForwarding_swift2.swift */; };
63937A6A21524C0B00AEE75A /* StoryboardInstantiatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63937A6921524C0B00AEE75A /* StoryboardInstantiatable.swift */; };
63937A6F21524DA300AEE75A /* DipUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63937A6B21524DA200AEE75A /* DipUITests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -74,17 +69,15 @@
09BD350B1D84E30D00B33E53 /* ThreadSafetyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ThreadSafetyTests.swift; path = ../../Tests/DipTests/ThreadSafetyTests.swift; sourceTree = "<group>"; };
09BD350C1D84E30D00B33E53 /* TypeForwardingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TypeForwardingTests.swift; path = ../../Tests/DipTests/TypeForwardingTests.swift; sourceTree = "<group>"; };
09BD350D1D84E30D00B33E53 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = ../../Tests/DipTests/Utils.swift; sourceTree = "<group>"; };
09FC48041DAA9AC700566AA8 /* Resolve_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Resolve_swift2.swift; path = ../../Sources/Resolve_swift2.swift; sourceTree = "<group>"; };
09FC48051DAA9AC700566AA8 /* Resolve.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Resolve.swift; path = ../../Sources/Resolve.swift; sourceTree = "<group>"; };
09FC480C1DAA9CAF00566AA8 /* Register.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Register.swift; path = ../../Sources/Register.swift; sourceTree = "<group>"; };
09FC480D1DAA9CAF00566AA8 /* Register_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Register_swift2.swift; path = ../../Sources/Register_swift2.swift; sourceTree = "<group>"; };
09FC48121DAA9E0200566AA8 /* AutoInjection_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AutoInjection_swift2.swift; path = ../../Sources/AutoInjection_swift2.swift; sourceTree = "<group>"; };
09FC48161DAAA53100566AA8 /* DipError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DipError.swift; path = ../../Sources/DipError.swift; sourceTree = "<group>"; };
09FC48171DAAA53100566AA8 /* DipError_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DipError_swift2.swift; path = ../../Sources/DipError_swift2.swift; sourceTree = "<group>"; };
09FC481A1DAAA82800566AA8 /* RuntimeArguments_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RuntimeArguments_swift2.swift; path = ../../Sources/RuntimeArguments_swift2.swift; sourceTree = "<group>"; };
09FC481C1DAAA8F900566AA8 /* ComponentScope.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComponentScope.swift; path = ../../Sources/ComponentScope.swift; sourceTree = "<group>"; };
09FC481D1DAAA8F900566AA8 /* ComponentScope_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComponentScope_swift2.swift; path = ../../Sources/ComponentScope_swift2.swift; sourceTree = "<group>"; };
09FC48201DAAAC4700566AA8 /* TypeForwarding_swift2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TypeForwarding_swift2.swift; path = ../../Sources/TypeForwarding_swift2.swift; sourceTree = "<group>"; };
63937A6921524C0B00AEE75A /* StoryboardInstantiatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StoryboardInstantiatable.swift; path = ../../Sources/StoryboardInstantiatable.swift; sourceTree = "<group>"; };
63937A6B21524DA200AEE75A /* DipUITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DipUITests.swift; path = ../../Tests/DipTests/DipUITests.swift; sourceTree = "<group>"; };
63937A6C21524DA200AEE75A /* NSStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NSStoryboard.storyboard; sourceTree = "<group>"; };
63937A6D21524DA300AEE75A /* TVStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = TVStoryboard.storyboard; sourceTree = "<group>"; };
63937A6E21524DA300AEE75A /* UIStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UIStoryboard.storyboard; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -112,23 +105,17 @@
0919F4C91C16417000DC3B10 /* Dip.h */,
0919F4CA1C16417000DC3B10 /* Dip.swift */,
09FC48161DAAA53100566AA8 /* DipError.swift */,
09FC48171DAAA53100566AA8 /* DipError_swift2.swift */,
09FC480C1DAA9CAF00566AA8 /* Register.swift */,
09FC480D1DAA9CAF00566AA8 /* Register_swift2.swift */,
09FC48051DAA9AC700566AA8 /* Resolve.swift */,
09FC48041DAA9AC700566AA8 /* Resolve_swift2.swift */,
0919F4C81C16417000DC3B10 /* Definition.swift */,
09FC481C1DAAA8F900566AA8 /* ComponentScope.swift */,
09FC481D1DAAA8F900566AA8 /* ComponentScope_swift2.swift */,
0919F4CC1C16417000DC3B10 /* RuntimeArguments.swift */,
09FC481A1DAAA82800566AA8 /* RuntimeArguments_swift2.swift */,
09873F551C1E0237000C02F6 /* AutoInjection.swift */,
09FC48121DAA9E0200566AA8 /* AutoInjection_swift2.swift */,
09B035FF1C5D2B83001EA5B7 /* AutoWiring.swift */,
095F829B1D043B41008CD706 /* TypeForwarding.swift */,
09FC48201DAAAC4700566AA8 /* TypeForwarding_swift2.swift */,
0982AF0B1C5183A000B62463 /* Utils.swift */,
09871B401DAA6BF300B40B91 /* Compatibility.swift */,
63937A6921524C0B00AEE75A /* StoryboardInstantiatable.swift */,
0919F4CB1C16417000DC3B10 /* Info.plist */,
);
path = Dip;
@@ -146,6 +133,10 @@
09BD350A1D84E30D00B33E53 /* RuntimeArgumentsTests.swift */,
09BD350B1D84E30D00B33E53 /* ThreadSafetyTests.swift */,
09BD350C1D84E30D00B33E53 /* TypeForwardingTests.swift */,
63937A6B21524DA200AEE75A /* DipUITests.swift */,
63937A6C21524DA200AEE75A /* NSStoryboard.storyboard */,
63937A6D21524DA300AEE75A /* TVStoryboard.storyboard */,
63937A6E21524DA300AEE75A /* UIStoryboard.storyboard */,
09BD350D1D84E30D00B33E53 /* Utils.swift */,
0919F4D11C16417000DC3B10 /* Info.plist */,
);
@@ -210,6 +201,7 @@
buildPhases = (
0903B35D1C161543002241C1 /* Sources */,
0903B35E1C161543002241C1 /* Frameworks */,
63937A7721524E3B00AEE75A /* ShellScript */,
0903B35F1C161543002241C1 /* Resources */,
);
buildRules = (
@@ -229,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 */;
@@ -277,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;
@@ -284,23 +297,17 @@
files = (
09871B411DAA6BF300B40B91 /* Compatibility.swift in Sources */,
0982AF0C1C5183A000B62463 /* Utils.swift in Sources */,
09FC481F1DAAA8F900566AA8 /* ComponentScope_swift2.swift in Sources */,
0919F4D51C16417B00DC3B10 /* Definition.swift in Sources */,
09FC48061DAA9AC700566AA8 /* Resolve_swift2.swift in Sources */,
09FC48101DAA9CAF00566AA8 /* Register_swift2.swift in Sources */,
09FC48191DAAA53100566AA8 /* DipError_swift2.swift in Sources */,
09FC481E1DAAA8F900566AA8 /* ComponentScope.swift in Sources */,
09FC48211DAAAC4700566AA8 /* TypeForwarding_swift2.swift in Sources */,
63937A6A21524C0B00AEE75A /* StoryboardInstantiatable.swift in Sources */,
09B036001C5D2B83001EA5B7 /* AutoWiring.swift in Sources */,
0919F4D41C16417B00DC3B10 /* Dip.swift in Sources */,
09FC481B1DAAA82800566AA8 /* RuntimeArguments_swift2.swift in Sources */,
09FC480F1DAA9CAF00566AA8 /* Register.swift in Sources */,
09FC48071DAA9AC700566AA8 /* Resolve.swift in Sources */,
095F829C1D043B41008CD706 /* TypeForwarding.swift in Sources */,
09873F561C1E0237000C02F6 /* AutoInjection.swift in Sources */,
09FC48181DAAA53100566AA8 /* DipError.swift in Sources */,
0919F4D61C16417B00DC3B10 /* RuntimeArguments.swift in Sources */,
09FC48141DAA9E0200566AA8 /* AutoInjection_swift2.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -310,6 +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 */,
@@ -353,6 +361,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.Dip;
PRODUCT_NAME = Dip;
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
@@ -372,6 +381,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.Dip;
PRODUCT_NAME = Dip;
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
};
name = Release;
};
@@ -387,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;
};
@@ -403,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;
};
@@ -410,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.0.4;
CURRENT_PROJECT_VERSION = 7.0.1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -452,12 +479,12 @@
ONLY_ACTIVE_ARCH = YES;
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
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;
};
@@ -465,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.0.4;
CURRENT_PROJECT_VERSION = 7.0.1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -500,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;
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
View File
@@ -9,7 +9,7 @@
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<string>7.1.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>7.1.1</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
+54
View File
@@ -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>
+75
View File
@@ -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>
+78
View File
@@ -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 -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.
+3
View File
@@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "cocoapods", '=1.4.0'
+76
View File
@@ -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
+8
View File
@@ -0,0 +1,8 @@
import XCTest
import DipTests
var tests = [XCTestCaseEntry]()
tests += DipTests.__allTests()
XCTMain(tests)
+9 -24
View File
@@ -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"),
]
)
+4 -18
View File
@@ -5,8 +5,8 @@
[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![License](https://img.shields.io/cocoapods/l/Dip.svg?style=flat)](http://cocoapods.org/pods/Dip)
[![Platform](https://img.shields.io/cocoapods/p/Dip.svg?style=flat)](http://cocoapods.org/pods/Dip)
[![Swift Version](https://img.shields.io/badge/Swift-2.3--3.0-F16D39.svg?style=flat)](https://developer.apple.com/swift)
[![Swift Version](https://img.shields.io/badge/Linux-3.0--RELEASE-4BC51D.svg?style=flat)](https://developer.apple.com/swift)
[![Swift Version](https://img.shields.io/badge/Swift-4.0--4.2-F16D39.svg?style=flat)](https://developer.apple.com/swift)
[![Swift Version](https://img.shields.io/badge/Linux-4.0--4.2-4BC51D.svg?style=flat)](https://developer.apple.com/swift)
![Animated Dipping GIF](cinnamon-pretzels-caramel-dipping.gif)
_Photo courtesy of [www.kevinandamanda.com](http://www.kevinandamanda.com/recipes/appetizer/homemade-soft-cinnamon-sugar-pretzel-bites-with-salted-caramel-dipping-sauce.html)_
@@ -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" : {
@@ -1,45 +0,0 @@
//
// BaseCell.swift
// Dip
//
// Created by Olivier Halligon on 10/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
protocol BaseCell {
static var identifier: String { get }
static var nib: UINib? { get }
static func register(_ tableView: UITableView)
static func dequeueFromTableView(_ tableView: UITableView, forIndexPath indexPath: IndexPath) -> Self
}
extension BaseCell where Self : UITableViewCell {
static var identifier: String {
return "\(Self.self)"
}
static var nib: UINib? { return nil }
static func register(_ tableView: UITableView) {
if let cellNib = self.nib {
tableView.register(cellNib, forCellReuseIdentifier: identifier)
} else {
tableView.register(Self.self as AnyClass, forCellReuseIdentifier: identifier)
}
}
<<<<<<< HEAD
static func dequeueFromTableView(tableView: UITableView, forIndexPath indexPath: NSIndexPath) -> Self {
=======
static func dequeueFromTableView(_ tableView: UITableView, forIndexPath indexPath: IndexPath) -> Self {
>>>>>>> feature/swift3
return tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) as! Self
}
}
protocol FillableCell: BaseCell {
associatedtype ObjectType
func fillWithObject(object: ObjectType)
}
@@ -1,48 +0,0 @@
//
// UserCell.swift
// Dip
//
// Created by Olivier Halligon on 10/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
final class PersonCell : UITableViewCell, FillableCell {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var genderImageView: UIImageView!
@IBOutlet weak var heightLabel: UILabel!
@IBOutlet weak var massLabel: UILabel!
@IBOutlet weak var hairLabel: UILabel!
@IBOutlet weak var eyesLabel: UILabel!
<<<<<<< HEAD
let heightFormatter: NSLengthFormatter = {
let f = NSLengthFormatter()
f.isForPersonHeightUse = true
return f
}()
let massFormatter: NSMassFormatter = {
let f = NSMassFormatter()
=======
let heightFormatter: LengthFormatter = {
let f = LengthFormatter()
f.isForPersonHeightUse = true
return f
}()
let massFormatter: MassFormatter = {
let f = MassFormatter()
>>>>>>> feature/swift3
f.isForPersonMassUse = true
return f
}()
func fillWithObject(object person: Person) {
nameLabel.text = person.name
genderImageView.image = person.gender.flatMap { UIImage(named: $0.rawValue) }
heightLabel.text = heightFormatter.string(fromValue: Double(person.height), unit: .centimeter)
massLabel.text = massFormatter.string(fromValue: Double(person.mass), unit: .kilogram)
hairLabel.text = person.hairColor
eyesLabel.text = person.eyeColor
}
}
+1 -1
View File
@@ -9,7 +9,7 @@
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<string>7.1.1</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
@@ -1,126 +0,0 @@
//
// PlistPersonProvider.swift
// Dip
//
// Created by Ilya Puchka on 12/09/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
///Provides some dummy Person entities
struct DummyPilotProvider : PersonProviderAPI {
func fetchIDs(completion: ([Int]) -> Void) {
completion(Array(0..<5))
}
<<<<<<< HEAD
func fetch(id: Int, completion: Person? -> Void) {
=======
func fetch(id: Int, completion: (Person?) -> Void) {
>>>>>>> feature/swift3
completion(dummyPerson(idx: id))
}
private func dummyPerson(idx: Int) -> Person {
let colors = ["blue", "brown", "yellow", "orange", "red", "dark"]
let genders: [Gender?] = [Gender.Male, Gender.Female, nil]
return Person(
name: "John Dummy Doe #\(idx)",
height: 150 + (idx*27%40),
mass: 50 + (idx*7%30),
hairColor: colors[idx*3%colors.count],
eyeColor: colors[idx*2%colors.count],
gender: genders[idx%3],
starshipIDs: [idx % 3, 2*idx % 4]
)
}
}
///Provides Person entities reading then from plist file
class PlistPersonProvider : PersonProviderAPI {
let people: [Person]
init(plist basename: String) {
guard
<<<<<<< HEAD
let path = NSBundle.main().pathForResource(basename, ofType: "plist"),
=======
let path = Bundle.main().pathForResource(basename, ofType: "plist"),
>>>>>>> feature/swift3
let list = NSArray(contentsOfFile: path),
peopleDict = list as? [[String:AnyObject]]
else {
fatalError("PLIST for \(basename) not found")
}
self.people = peopleDict.map(PlistPersonProvider.personFromDict)
}
func fetchIDs(completion: ([Int]) -> Void) {
completion(Array(0..<people.count))
}
func fetch(id: Int, completion: (Person?) -> Void) {
guard id < people.count else {
completion(nil)
return
}
completion(people[id])
}
private static func personFromDict(dict: [String:AnyObject]) -> Person {
guard
let name = dict["name"] as? String,
height = dict["height"] as? Int,
mass = dict["mass"] as? Int,
hairColor = dict["hairColor"] as? String,
eyeColor = dict["eyeColor"] as? String,
genderStr = dict["gender"] as? String,
starshipsIDs = dict["starships"] as? [Int]
else {
fatalError("Invalid Plist")
}
return Person(
name: name,
height: height,
mass: mass,
hairColor: hairColor,
eyeColor: eyeColor,
gender: Gender(rawValue: genderStr),
starshipIDs: starshipsIDs
)
}
}
class FakePersonsProvider: PersonProviderAPI {
let dummyProvider: PersonProviderAPI
var plistProvider: PersonProviderAPI!
//In this class we use both constructor injection and property injection,
//nil is a valid local default
init(dummyProvider: PersonProviderAPI) {
self.dummyProvider = dummyProvider
}
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
>>>>>>> feature/swift3
dummyProvider.fetchIDs(completion: completion)
}
func fetch(id: Int, completion: (Person?) -> Void) {
if let plistProvider = plistProvider where id == 0 {
plistProvider.fetch(id: id, completion: completion)
}
else {
dummyProvider.fetch(id: id, completion: completion)
}
}
}
@@ -13,7 +13,7 @@ struct DummyStarshipProvider : StarshipProviderAPI {
var pilotName: String
func fetchIDs(completion: @escaping ([Int]) -> Void) {
let nbShips = pilotName.characters.count
let nbShips = pilotName.count
completion(Array(0..<nbShips))
}
@@ -1,92 +0,0 @@
//
// FakeStarshipProvider.swift
// DipSampleApp
//
// Created by Ilya Puchka on 20.01.16.
// Copyright © 2016 AliSoftware. All rights reserved.
//
import Foundation
///Provides some dummy Starship entities
struct DummyStarshipProvider : StarshipProviderAPI {
var pilotName: String
func fetchIDs(completion: ([Int]) -> Void) {
let nbShips = pilotName.characters.count
completion(Array(0..<nbShips))
}
<<<<<<< HEAD
func fetch(id: Int, completion: Starship? -> Void) {
=======
func fetch(id: Int, completion: (Starship?) -> Void) {
>>>>>>> feature/swift3
completion(dummyStarship(idx: id))
}
private func dummyStarship(idx: Int) -> Starship {
return Starship(
name: "\(pilotName)'s awesome starship #\(idx)",
model: "\(pilotName)Ship",
manufacturer: "Dummy Industries",
crew: 1 + (idx%3),
passengers: 10 + (idx*7 % 40),
pilotIDs: [idx]
)
}
}
///Provides hardcoded Starship entities stored in memory
class HardCodedStarshipProvider : StarshipProviderAPI {
let starships = [
Starship(name: "First Ship", model: "AwesomeShip", manufacturer: "HardCoded Inc.", crew: 3, passengers: 20, pilotIDs: [1,2]),
Starship(name: "Second Ship", model: "AwesomeShip Express", manufacturer: "HardCoded Inc.", crew: 4, passengers: 10, pilotIDs: [1]),
Starship(name: "Third Ship", model: "AwesomeShip Cargo", manufacturer: "HardCoded Inc.", crew: 12, passengers: 150, pilotIDs: [2]),
] + Array(4..<75).map { Starship(name: "Ship #\($0)", model: "AwesomeShip Fighter", manufacturer: "HardCoded Inc.", crew: 1, passengers: 2, pilotIDs: [1]) }
func fetchIDs(completion: ([Int]) -> Void) {
completion(Array(0..<starships.count))
}
func fetch(id: Int, completion: (Starship?) -> Void) {
guard id < starships.count else {
completion(nil)
return
}
completion(starships[id])
}
}
class FakeStarshipProvider: StarshipProviderAPI {
let dummyProvider: StarshipProviderAPI
let hardCodedProvider: StarshipProviderAPI
//Constructor injection again here
init(dummyProvider: StarshipProviderAPI, hardCodedProvider: StarshipProviderAPI) {
self.dummyProvider = dummyProvider
self.hardCodedProvider = hardCodedProvider
}
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
>>>>>>> feature/swift3
hardCodedProvider.fetchIDs(completion: completion)
}
func fetch(id: Int, completion: (Starship?) -> Void) {
if id == 0 {
dummyProvider.fetch(id: id, completion: completion)
}
else {
hardCodedProvider.fetch(id: id, completion: completion)
}
}
}
@@ -1,40 +0,0 @@
//
// NetworkLayer.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
enum NetworkResponse {
case Success(Data, HTTPURLResponse)
case Error(NSError)
func unwrap() throws -> (Data, HTTPURLResponse) {
switch self {
case Success(let data, let response):
return (data, response)
case Error(let error):
throw error
}
}
func json<T>() throws -> T {
let (data, _) = try self.unwrap()
<<<<<<< HEAD
let obj = try NSJSONSerialization.jsonObject(with: data, options: [])
=======
let obj = try JSONSerialization.jsonObject(with: data, options: [])
>>>>>>> feature/swift3
guard let json = obj as? T else {
throw SWAPIError.InvalidJSON
}
return json
}
}
protocol NetworkLayer {
func request(path: String, completion: (NetworkResponse) -> Void)
}
@@ -27,8 +27,8 @@ struct SWAPIPersonProvider : PersonProviderAPI {
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
// Extract URLs (flatten to ignore invalid ones)
let urlStrings = results.flatMap({ $0["url"] as? String })
let ids = urlStrings.flatMap(idFromURLString)
let urlStrings = results.compactMap({ $0["url"] as? String })
let ids = urlStrings.compactMap(idFromURLString)
completion(ids)
}
@@ -61,7 +61,7 @@ struct SWAPIPersonProvider : PersonProviderAPI {
hairColor: hairColor,
eyeColor: eyeColor,
gender: Gender(rawValue: gender),
starshipIDs: starshipURLStrings.flatMap(idFromURLString)
starshipIDs: starshipURLStrings.compactMap(idFromURLString)
)
completion(person)
}
@@ -1,81 +0,0 @@
//
// SWAPIPersonProvider.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
///Provides Person entitis fetching them with web service
struct SWAPIPersonProvider : PersonProviderAPI {
let ws: NetworkLayer
//Here we inject dependency using _constructor injection_ pattern.
//The alternative way is a _property injection_
//but it should be used only for optional dependencies
//where there is a good local default implementation
init(webService: NetworkLayer) {
self.ws = webService
}
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
>>>>>>> feature/swift3
ws.request(path: "people") { response in
do {
let dict = try response.json() as NSDictionary
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
// Extract URLs (flatten to ignore invalid ones)
let urlStrings = results.flatMap({ $0["url"] as? String })
let ids = urlStrings.flatMap(idFromURLString)
completion(ids)
}
catch {
completion([])
}
}
}
<<<<<<< HEAD
func fetch(id: Int, completion: Person? -> Void) {
=======
func fetch(id: Int, completion: (Person?) -> Void) {
>>>>>>> feature/swift3
ws.request(path: "people/\(id)") { response in
do {
let json = try response.json() as NSDictionary
guard
let name = json["name"] as? String,
let heightStr = json["height"] as? String, height = Int(heightStr),
let massStr = json["mass"] as? String, mass = Int(massStr),
let hairColor = json["hair_color"] as? String,
let eyeColor = json["eye_color"] as? String,
let gender = json["gender"] as? String,
let starshipURLStrings = json["starships"] as? [String]
else {
throw SWAPIError.InvalidJSON
}
let person = Person(
name: name,
height: height,
mass: mass,
hairColor: hairColor,
eyeColor: eyeColor,
gender: Gender(rawValue: gender),
starshipIDs: starshipURLStrings.flatMap(idFromURLString)
)
completion(person)
}
catch {
completion(nil)
}
}
}
}
@@ -27,8 +27,8 @@ struct SWAPIStarshipProvider : StarshipProviderAPI {
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
// Extract URLs (flatten to ignore invalid ones)
let urlStrings = results.flatMap({ $0["url"] as? String })
let ids = urlStrings.flatMap(idFromURLString)
let urlStrings = results.compactMap({ $0["url"] as? String })
let ids = urlStrings.compactMap(idFromURLString)
completion(ids)
}
@@ -59,7 +59,7 @@ struct SWAPIStarshipProvider : StarshipProviderAPI {
manufacturer: manufacturer,
crew: crew,
passengers: passengers,
pilotIDs: pilotIDStrings.flatMap(idFromURLString)
pilotIDs: pilotIDStrings.compactMap(idFromURLString)
)
completion(ship)
}
@@ -1,79 +0,0 @@
//
// SWAPIStarshipProvider.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
///Provides Starship entities fetching them using web service
struct SWAPIStarshipProvider : StarshipProviderAPI {
let ws: NetworkLayer
//Here we inject dependency using _constructor injection_ pattern.
//The alternative way is a _property injection_
//but it should be used only for optional dependencies
//where there is a good local default implementation
init(webService: NetworkLayer) {
self.ws = webService
}
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
>>>>>>> feature/swift3
ws.request(path: "starships") { response in
do {
let dict = try response.json() as NSDictionary
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
// Extract URLs (flatten to ignore invalid ones)
let urlStrings = results.flatMap({ $0["url"] as? String })
let ids = urlStrings.flatMap(idFromURLString)
completion(ids)
}
catch {
completion([])
}
}
}
<<<<<<< HEAD
func fetch(id: Int, completion: Starship? -> Void) {
=======
func fetch(id: Int, completion: (Starship?) -> Void) {
>>>>>>> feature/swift3
ws.request(path: "starships/\(id)") { response in
do {
let json = try response.json() as NSDictionary
guard
let name = json["name"] as? String,
let model = json["model"] as? String,
let manufacturer = json["manufacturer"] as? String,
let crewStr = json["crew"] as? String, crew = Int(crewStr),
let passengersStr = json["passengers"] as? String, passengers = Int(passengersStr),
let pilotIDStrings = json["pilots"] as? [String]
else {
throw SWAPIError.InvalidJSON
}
let ship = Starship(
name: name,
model: model,
manufacturer: manufacturer,
crew: crew,
passengers: passengers,
pilotIDs: pilotIDStrings.flatMap(idFromURLString)
)
completion(ship)
}
catch {
completion(nil)
}
}
}
}
@@ -1,66 +0,0 @@
//
// URLSessionNetworkLayer.swift
// Dip
//
// Created by Olivier Halligon on 10/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
///NetworkLayer implementation on top of NSURLSession
struct URLSessionNetworkLayer : NetworkLayer {
let baseURL: URL
let session: URLSession
let responseQueue: DispatchQueue
<<<<<<< HEAD
init?(baseURL: String, session: NSURLSession = NSURLSession.shared(), responseQueue: dispatch_queue_t = dispatch_get_main_queue()) {
guard let url = NSURL(string: baseURL) else { return nil }
self.init(baseURL: url, session: session)
}
init(baseURL: NSURL, session: NSURLSession = .shared(), responseQueue: dispatch_queue_t = dispatch_get_main_queue()) {
=======
init?(baseURL: String, session: URLSession = .shared(), responseQueue: DispatchQueue = DispatchQueue.main) {
guard let url = URL(string: baseURL) else { return nil }
self.init(baseURL: url, session: session)
}
init(baseURL: URL, session: URLSession = .shared(), responseQueue: DispatchQueue = DispatchQueue.main) {
>>>>>>> feature/swift3
self.baseURL = baseURL
self.session = session
self.responseQueue = responseQueue
}
<<<<<<< HEAD
func request(path: String, completion: NetworkResponse -> Void) {
let url = self.baseURL.appendingPathComponent(path)
let task = session.dataTask(with: url) { data, response, error in
if let data = data, let response = response as? NSHTTPURLResponse {
dispatch_async(self.responseQueue) {
=======
func request(path: String, completion: (NetworkResponse) -> Void) {
guard let url = try? self.baseURL.appendingPathComponent(path) else { return }
let task = session.dataTask(with: url) { data, response, error in
if let data = data, let response = response as? HTTPURLResponse {
self.responseQueue.async() {
>>>>>>> feature/swift3
completion(NetworkResponse.Success(data, response))
}
}
else {
let err = error ?? NSError(domain: NSURLErrorDomain, code: NSURLError.unknown.rawValue, userInfo: nil)
<<<<<<< HEAD
dispatch_async(self.responseQueue) {
=======
self.responseQueue.async() {
>>>>>>> feature/swift3
completion(NetworkResponse.Error(err))
}
}
}
task.resume()
}
}
@@ -1,73 +0,0 @@
//
// PersonListViewController.swift
// Dip
//
// Created by Olivier Halligon on 09/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
class PersonListViewController: UITableViewController, FetchableTrait {
var objects: [Person]?
var batchRequestID = 0
var personProvider: PersonProviderAPI!
var starshipProvider: StarshipProviderAPI!
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
return personProvider.fetchIDs(completion: completion)
}
func fetchOne(id personID: Int, completion: Person? -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
return personProvider.fetchIDs(completion: completion)
}
func fetchOne(id personID: Int, completion: (Person?) -> Void) {
>>>>>>> feature/swift3
return personProvider.fetch(id: personID, completion: completion)
}
var fetchProgress: (current: Int, total: Int?) = (0, nil) {
didSet {
displayProgressInNavBar(navigationItem: self.navigationItem)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
guard
let id = segue.identifier, segueID = UIStoryboard.Segue.Main(rawValue: id)
where segueID == .StarshipsSegue,
let indexPath = self.tableView.indexPathForSelectedRow,
let destVC = segue.destinationViewController as? StarshipListViewController,
let person = self.objects?[indexPath.row]
else {
fatalError()
}
destVC.starshipProvider = starshipProvider
destVC.loadObjects(objectIDs: person.starshipIDs)
}
}
extension PersonListViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}
<<<<<<< HEAD
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: NSIndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = PersonCell.dequeueFromTableView(tableView: tableView, forIndexPath: indexPath)
=======
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = PersonCell.dequeueFromTableView(tableView, forIndexPath: indexPath)
>>>>>>> feature/swift3
cell.fillWithObject(object: object)
return cell
}
}
@@ -1,72 +0,0 @@
//
// StarshipListViewController.swift
// Dip
//
// Created by Olivier Halligon on 09/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import UIKit
import Dip
class StarshipListViewController : UITableViewController, FetchableTrait {
var objects: [Starship]?
var batchRequestID = 0
var starshipProvider: StarshipProviderAPI!
var personProvider: PersonProviderAPI!
<<<<<<< HEAD
func fetchIDs(completion: [Int] -> Void) {
starshipProvider.fetchIDs(completion: completion)
}
func fetchOne(id shipID:Int, completion: Starship? -> Void) {
=======
func fetchIDs(completion: ([Int]) -> Void) {
starshipProvider.fetchIDs(completion: completion)
}
func fetchOne(id shipID:Int, completion: (Starship?) -> Void) {
>>>>>>> feature/swift3
starshipProvider.fetch(id: shipID, completion: completion)
}
var fetchProgress: (current: Int, total: Int?) = (0, nil) {
didSet {
displayProgressInNavBar(navigationItem: self.navigationItem)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
guard
let id = segue.identifier, segueID = UIStoryboard.Segue.Main(rawValue: id)
where segueID == .PilotsSegue,
let indexPath = self.tableView.indexPathForSelectedRow,
let destVC = segue.destinationViewController as? PersonListViewController,
let starship = self.objects?[indexPath.row]
else {
fatalError()
}
destVC.personProvider = personProvider
destVC.loadObjects(objectIDs: starship.pilotIDs)
}
}
extension StarshipListViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}
<<<<<<< HEAD
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: NSIndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = StarshipCell.dequeueFromTableView(tableView: tableView, forIndexPath: indexPath)
=======
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let object = self.objects?[indexPath.row] else { fatalError() }
let cell = StarshipCell.dequeueFromTableView(tableView, forIndexPath: indexPath)
>>>>>>> feature/swift3
cell.fillWithObject(object: object)
return cell
}
}
+1 -1
View File
@@ -9,7 +9,7 @@
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<string>7.1.1</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
-52
View File
@@ -1,52 +0,0 @@
//
// NetworkMock.swift
// Dip
//
// Created by Olivier Halligon on 11/10/2015.
// Copyright © 2015 AliSoftware. All rights reserved.
//
import Foundation
import Dip
var wsDependencies = DependencyContainer()
// MARK: - Mock object used for tests
struct NetworkMock : NetworkLayer {
let fakeData: Data?
init(json: AnyObject) {
do {
<<<<<<< HEAD
fakeData = try NSJSONSerialization.data(withJSONObject: json, options: [])
=======
fakeData = try JSONSerialization.data(withJSONObject: json, options: [])
>>>>>>> feature/swift3
} catch {
fakeData = nil
}
}
<<<<<<< HEAD
func request(path: String, completion: NetworkResponse -> Void) {
let fakeURL = NSURL(string: "stub://")!.appendingPathComponent(path)
if let data = fakeData {
let response = NSHTTPURLResponse(url: fakeURL, statusCode: 200, httpVersion: "1.1", headerFields:nil)!
completion(.Success(data, response))
} else {
let response = NSHTTPURLResponse(url: fakeURL, statusCode: 204, httpVersion: "1.1", headerFields:nil)!
completion(.Success(NSData(), response))
=======
func request(path: String, completion: (NetworkResponse) -> Void) {
let fakeURL = try! URL(string: "stub://")!.appendingPathComponent(path)
if let data = fakeData {
let response = HTTPURLResponse(url: fakeURL, statusCode: 200, httpVersion: "1.1", headerFields:nil)!
completion(.Success(data, response))
} else {
let response = HTTPURLResponse(url: fakeURL, statusCode: 204, httpVersion: "1.1", headerFields:nil)!
completion(.Success(Data(), response))
>>>>>>> feature/swift3
}
}
}
+213 -131
View File
@@ -33,27 +33,21 @@ extension DependencyContainer {
//mirror only contains class own properties
//so we need to walk through super class mirrors
//to resolve super class auto-injected properties
var superClassMirror = mirror._superclassMirror
var superClassMirror = mirror.superclassMirror
while superClassMirror != nil {
try superClassMirror?.children.forEach(resolveChild)
superClassMirror = superClassMirror?._superclassMirror
superClassMirror = superClassMirror?.superclassMirror
}
try mirror.children.forEach(resolveChild)
}
private func resolveChild(child: Mirror.Child) throws {
#if swift(>=3.0)
//HOTFIX for https://bugs.swift.org/browse/SR-2282
guard !String(describing: type(of: child.value)).has(prefix: "ImplicitlyUnwrappedOptional") else { return }
#endif
//HOTFIX for https://bugs.swift.org/browse/SR-2282
guard !String(describing: type(of: child.value)).has(prefix: "ImplicitlyUnwrappedOptional") else { return }
guard let injectedPropertyBox = child.value as? AutoInjectedPropertyBox else { return }
#if swift(>=3.0)
let wrappedType = type(of: injectedPropertyBox).wrappedType
#else
let wrappedType = injectedPropertyBox.dynamicType.wrappedType
#endif
let wrappedType = type(of: injectedPropertyBox).wrappedType
let contextKey = DefinitionKey(type: wrappedType, typeOfArguments: Void.self, tag: context.tag)
try inContext(key:contextKey, injectedInType: context?.resolvingType, injectedInProperty: child.label, logErrors: false) {
try injectedPropertyBox.resolve(self)
@@ -84,11 +78,10 @@ extension DependencyContainer {
```
*/
public protocol AutoInjectedPropertyBox: class {
public protocol AutoInjectedPropertyBox {
///The type of wrapped property.
static var wrappedType: Any.Type { get }
#if swift(>=3.0)
/**
This method will be called by `DependencyContainer` during processing resolved instance properties.
In this method you should resolve an instance for wrapped property and store a reference to it.
@@ -98,51 +91,112 @@ public protocol AutoInjectedPropertyBox: class {
- note: This method is not intended to be called manually, `DependencyContainer` will call it by itself.
*/
func resolve(_ container: DependencyContainer) throws
#else
/**
This method will be called by `DependencyContainer` during processing resolved instance properties.
In this method you should resolve an instance for wrapped property and store a reference to it.
- parameter container: A container to be used to resolve an instance
- note: This method is not intended to be called manually, `DependencyContainer` will call it by itself.
*/
func resolve(container: DependencyContainer) throws
#endif
}
#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.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
}
#if swift(>=3.0)
/**
Creates a new wrapper for auto-injected property.
@@ -154,42 +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)
}
init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> ()) {
self.value = value
super.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
}
public func resolve(_ container: DependencyContainer) throws {
let resolved: T? = try super.resolve(with: container)
value = resolved
}
/// 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)
}
#else
init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: (T) -> ()) {
self.value = value
super.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
}
#endif
}
#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.
@@ -211,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
}
#if swift(>=3.0)
init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> ()) {
self.valueBox = value.map(WeakBox.init)
super.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
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.
@@ -258,66 +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)
}
#else
init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: (T) -> ()) {
self.valueBox = value.map(WeakBox.init)
super.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
}
#endif
}
class _InjectedPropertyBox<T> {
protocol _InjectedPropertyBox {}
let required: Bool
let didInject: (T) -> ()
let tag: DependencyContainer.Tag?
let overrideTag: Bool
#if swift(>=3.0)
init(required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> () = { _ in }) {
self.required = required
self.tag = tag?.dependencyTag
self.overrideTag = overrideTag
self.didInject = didInject
}
#else
init(required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: (T) -> () = { _ in }) {
self.required = required
self.tag = tag?.dependencyTag
self.overrideTag = overrideTag
self.didInject = didInject
}
#endif
func resolve(with container: DependencyContainer) throws -> T? {
let tag = overrideTag ? self.tag : container.context.tag
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)
@@ -331,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)
})
}
}
-98
View File
@@ -1,98 +0,0 @@
//
// Dip
//
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if !swift(>=3.0)
extension Injected {
/**
Creates a new wrapper for auto-injected property.
- parameters:
- required: Defines if the property is required or not.
If container fails to inject required property it will als fail to resolve
the instance that defines that property. Default is `true`.
- tag: An optional tag to use to lookup definitions when injecting this property. Default is `nil`.
- didInject: block that will be called when concrete instance is injected in this property.
Similar to `didSet` property observer. Default value does nothing.
*/
public convenience init(required: Bool = true, didInject: (T) -> () = { _ in }) {
self.init(value: nil, required: required, tag: nil, overrideTag: false, didInject: didInject)
}
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: (T) -> () = { _ in }) {
self.init(value: nil, required: required, tag: tag, overrideTag: true, didInject: didInject)
}
public func resolve(container: DependencyContainer) throws {
let resolved: T? = try super.resolve(with: container)
value = resolved
}
/// Returns a new wrapper with provided value.
public func setValue(value: T?) -> Injected {
guard (required && value != nil) || !required else {
fatalError("Can not set required property to nil.")
}
return Injected(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
}
}
extension InjectedWeak {
/**
Creates a new wrapper for weak auto-injected property.
- parameters:
- required: Defines if the property is required or not.
If container fails to inject required property it will als fail to resolve
the instance that defines that property. Default is `true`.
- tag: An optional tag to use to lookup definitions when injecting this property. Default is `nil`.
- didInject: block that will be called when concrete instance is injected in this property.
Similar to `didSet` property observer. Default value does nothing.
*/
public convenience init(required: Bool = true, didInject: (T) -> () = { _ in }) {
self.init(value: nil, required: required, tag: nil, overrideTag: false, didInject: didInject)
}
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: (T) -> () = { _ in }) {
self.init(value: nil, required: required, tag: tag, overrideTag: true, didInject: didInject)
}
public func resolve(container: DependencyContainer) throws {
let resolved: T? = try super.resolve(with: container)
valueBox = resolved.map(WeakBox.init)
}
/// Returns a new wrapper with provided value.
public func setValue(value: T?) -> InjectedWeak {
guard (required && value != nil) || !required else {
fatalError("Can not set required property to nil.")
}
return InjectedWeak(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
}
}
#endif
+15 -4
View File
@@ -50,19 +50,30 @@ extension DependencyContainer {
}
private func autoWiringDefinition(byKey key: DefinitionKey) throws -> KeyDefinitionPair {
do {
return try autoWiringDefinition(byKey: key, strictByTag: true)
} catch {
if key.tag != nil {
return try autoWiringDefinition(byKey: key, strictByTag: false)
} else {
throw error
}
}
}
private func autoWiringDefinition(byKey key: DefinitionKey, strictByTag: Bool) throws -> KeyDefinitionPair {
var definitions = self.definitions.map({ (key: $0.0, definition: $0.1) })
definitions = filter(definitions: definitions, byKey: key)
definitions = filter(definitions: definitions, byKey: key, strictByTag: strictByTag)
definitions = definitions.sorted(by: { $0.definition.numberOfArguments > $1.definition.numberOfArguments })
guard definitions.count > 0 && definitions[0].definition.numberOfArguments > 0 else {
throw DipError.definitionNotFound(key: key)
}
let maximumNumberOfArguments = definitions.first?.definition.numberOfArguments
definitions = definitions.filter({ $0.definition.numberOfArguments == maximumNumberOfArguments })
definitions = order(definitions: definitions, byTag: key.tag)
//when there are several definitions with the same number of arguments but different arguments types
if definitions.count > 1 && definitions[0].key.typeOfArguments != definitions[1].key.typeOfArguments {
let error = DipError.ambiguousDefinitions(type: key.type, definitions: definitions.map({ $0.definition }))
+4 -74
View File
@@ -1,75 +1,5 @@
#if swift(>=3.0)
extension Mirror {
var _superclassMirror: Mirror? {
return superclassMirror
}
extension String {
func has(prefix aPrefix: String) -> Bool {
return hasPrefix(aPrefix)
}
#else
public typealias Error = ErrorType
public typealias ExpressibleByIntegerLiteral = IntegerLiteralConvertible
public typealias ExpressibleByStringLiteral = StringLiteralConvertible
extension CollectionType {
func sorted(@noescape by isOrderedBefore: (Self.Generator.Element, Self.Generator.Element) -> Bool) -> [Self.Generator.Element] {
return sort(isOrderedBefore)
}
func contains(@noescape where predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Bool {
return try contains(predicate)
}
}
extension CollectionType where Index : RandomAccessIndexType {
@warn_unused_result
func reversed() -> ReverseRandomAccessCollection<Self> {
return reverse()
}
}
extension SequenceType where Generator.Element == String {
@warn_unused_result
func joined(separator aSeparator: String) -> String {
return joinWithSeparator(aSeparator)
}
}
extension Array {
mutating func append<C : CollectionType where C.Generator.Element == Element>(contentsOf newElements: C) {
appendContentsOf(newElements)
}
mutating func append<S : SequenceType where S.Generator.Element == Element>(contentsOf newElements: S) {
appendContentsOf(newElements)
}
}
extension Mirror {
var _superclassMirror: Mirror? {
return superclassMirror()
}
}
extension String {
init(describing thing: Any) {
self.init(thing)
}
}
#endif
#if _runtime(_ObjC)
extension String {
func has(prefix aPrefix: String) -> Bool {
return hasPrefix(aPrefix)
}
}
#else
extension String {
func has(prefix aPrefix: String) -> Bool {
return aPrefix ==
String(self.characters.prefix(aPrefix.characters.count))
}
}
#endif
}
+95 -99
View File
@@ -22,103 +22,99 @@
// THE SOFTWARE.
//
#if swift(>=3.0)
///Component scope defines a strategy used by the `DependencyContainer` to manage resolved instances life cycle.
public enum ComponentScope {
/**
A new instance will be created every time it's resolved.
This is a default strategy. Use this strategy when you don't want instances to be shared
between different consumers (i.e. if it is not thread safe).
**Example**:
```
container.register { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer = container.resolve() as ServiceConsumer
consumer.service1 !== consumer.service2 //true
```
*/
case unique
/**
Instance resolved with the same definition will be reused until topmost `resolve(tag:)` method returns.
When you resolve the same object graph again the container will create new instances.
Use this strategy if you want different object in objects graph to share the same instance.
- warning: Make sure this component is thread safe or accessed always from the same thread.
**Example**:
```
container.register { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer1 = container.resolve() as ServiceConsumer
let consumer2 = container.resolve() as ServiceConsumer
consumer1.service1 === consumer1.service2 //true
consumer2.service1 === consumer2.service2 //true
consumer1.service1 !== consumer2.service1 //true
```
*/
case shared
/**
Resolved instance will be retained by the container and always reused.
Do not mix this life cycle with _singleton pattern_.
Instance will be not shared between different containers unless they collaborate.
- warning: Make sure this component is thread safe or accessed always from the same thread.
- note: When you override or remove definition from the container an instance
that was resolved with this definition will be released. When you reset
the container it will release all singleton instances.
**Example**:
```
container.register(.singleton) { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer1 = container.resolve() as ServiceConsumer
let consumer2 = container.resolve() as ServiceConsumer
consumer1.service1 === consumer1.service2 //true
consumer2.service1 === consumer2.service2 //true
consumer1.service1 === consumer2.service1 //true
```
*/
case singleton
/**
The same scope as a `Singleton`, but instance will be created when container is bootstrapped.
- seealso: `bootstrap()`
*/
case eagerSingleton
/**
The same scope as a `Singleton`, but container stores week reference to the resolved instance.
While a strong reference to the resolved instance exists resolve will return the same instance.
After the resolved instance is deallocated next resolve will produce a new instance.
*/
case weakSingleton
}
///Component scope defines a strategy used by the `DependencyContainer` to manage resolved instances life cycle.
public enum ComponentScope {
#endif
/**
A new instance will be created every time it's resolved.
This is a default strategy. Use this strategy when you don't want instances to be shared
between different consumers (i.e. if it is not thread safe).
**Example**:
```
container.register { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer = container.resolve() as ServiceConsumer
consumer.service1 !== consumer.service2 //true
```
*/
case unique
/**
Instance resolved with the same definition will be reused until topmost `resolve(tag:)` method returns.
When you resolve the same object graph again the container will create new instances.
Use this strategy if you want different object in objects graph to share the same instance.
- warning: Make sure this component is thread safe or accessed always from the same thread.
**Example**:
```
container.register { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer1 = container.resolve() as ServiceConsumer
let consumer2 = container.resolve() as ServiceConsumer
consumer1.service1 === consumer1.service2 //true
consumer2.service1 === consumer2.service2 //true
consumer1.service1 !== consumer2.service1 //true
```
*/
case shared
/**
Resolved instance will be retained by the container and always reused.
Do not mix this life cycle with _singleton pattern_.
Instance will be not shared between different containers unless they collaborate.
- warning: Make sure this component is thread safe or accessed always from the same thread.
- note: When you override or remove definition from the container an instance
that was resolved with this definition will be released. When you reset
the container it will release all singleton instances.
**Example**:
```
container.register(.singleton) { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer1 = container.resolve() as ServiceConsumer
let consumer2 = container.resolve() as ServiceConsumer
consumer1.service1 === consumer1.service2 //true
consumer2.service1 === consumer2.service2 //true
consumer1.service1 === consumer2.service1 //true
```
*/
case singleton
/**
The same scope as a `Singleton`, but instance will be created when container is bootstrapped.
- seealso: `bootstrap()`
*/
case eagerSingleton
/**
The same scope as a `Singleton`, but container stores week reference to the resolved instance.
While a strong reference to the resolved instance exists resolve will return the same instance.
After the resolved instance is deallocated next resolve will produce a new instance.
*/
case weakSingleton
}
-129
View File
@@ -1,129 +0,0 @@
//
// Dip
//
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if !swift(>=3.0)
///Component scope defines a strategy used by the `DependencyContainer` to manage resolved instances life cycle.
public enum ComponentScope {
/**
A new instance will be created every time it's resolved.
This is a default strategy. Use this strategy when you don't want instances to be shared
between different consumers (i.e. if it is not thread safe).
**Example**:
```
container.register { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer = container.resolve() as ServiceConsumer
consumer.service1 !== consumer.service2 //true
```
*/
case Unique
/**
Instance resolved with the same definition will be reused until topmost `resolve(tag:)` method returns.
When you resolve the same object graph again the container will create new instances.
Use this strategy if you want different object in objects graph to share the same instance.
- warning: Make sure this component is thread safe or accessed always from the same thread.
**Example**:
```
container.register { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer1 = container.resolve() as ServiceConsumer
let consumer2 = container.resolve() as ServiceConsumer
consumer1.service1 === consumer1.service2 //true
consumer2.service1 === consumer2.service2 //true
consumer1.service1 !== consumer2.service1 //true
```
*/
case Shared
/**
Resolved instance will be retained by the container and always reused.
Do not mix this life cycle with _singleton pattern_.
Instance will be not shared between different containers unless they collaborate.
- warning: Make sure this component is thread safe or accessed always from the same thread.
- note: When you override or remove definition from the container an instance
that was resolved with this definition will be released. When you reset
the container it will release all singleton instances.
**Example**:
```
container.register(.singleton) { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer1 = container.resolve() as ServiceConsumer
let consumer2 = container.resolve() as ServiceConsumer
consumer1.service1 === consumer1.service2 //true
consumer2.service1 === consumer2.service2 //true
consumer1.service1 === consumer2.service1 //true
```
*/
case Singleton
/**
The same scope as a `Singleton`, but instance will be created when container is bootstrapped.
- seealso: `bootstrap()`
*/
case EagerSingleton
/**
The same scope as a `Singleton`, but container stores week reference to the resolved instance.
While a strong reference to the resolved instance exists resolve will return the same instance.
After the resolved instance is deallocated next resolve will produce a new instance.
*/
case WeakSingleton
static var unique: ComponentScope { return .Unique }
static var shared: ComponentScope { return .Shared }
static var singleton: ComponentScope { return .Singleton }
static var weakSingleton: ComponentScope { return .WeakSingleton }
static var eagerSingleton: ComponentScope { return .EagerSingleton }
}
#endif
+47 -63
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?
@@ -34,12 +34,14 @@ public struct DefinitionKey : Hashable, CustomStringConvertible {
self.tag = tag
}
public var hashValue: Int {
return "\(type)-\(typeOfArguments)-\(tag)".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,20 +82,13 @@ public final class Definition<T, U>: DefinitionType {
let scope: ComponentScope
var weakFactory: ((Any) throws -> Any)!
var resolveProperties: ((DependencyContainer, Any) throws -> ())?
var autoInjectProperties: Bool?
#if swift(>=3.0)
init(scope: ComponentScope, factory: @escaping F) {
self.factory = factory
self.scope = scope
}
#else
init(scope: ComponentScope, factory: F) {
self.factory = factory
self.scope = scope
}
#endif
#if swift(>=3.0)
/**
Set the block that will be used to resolve dependencies of the instance.
This block will be called before `resolve(tag:)` returns.
@@ -132,46 +127,34 @@ public final class Definition<T, U>: DefinitionType {
}
return self
}
#else
@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)
}
}
/**
Set the block that will be used to resolve dependencies of the instance.
This block will be called before `resolve(tag:)` returns.
- parameter block: The block to resolve property dependencies of the instance.
- returns: modified definition
- note: To resolve circular dependencies at least one of them should use this block
to resolve its dependencies. Otherwise the application will enter an infinite loop and crash.
- note: You can call this method several times on the same definition.
Container will call all provided blocks in the same order.
**Example**
```swift
container.register { ClientImp(service: try container.resolve() as Service) as Client }
container.register { ServiceImp() as Service }
.resolvingProperties { container, service in
service.client = try container.resolve() as Client
}
```
*/
public func resolvingProperties(block: (DependencyContainer, T) throws -> ()) -> Definition {
if let oldBlock = self.resolveProperties {
self.resolveProperties = {
try oldBlock($0, $1 as! T)
try block($0, $1 as! T)
}
}
else {
self.resolveProperties = { try block($0, $1 as! T) }
}
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
}
#endif
/// Calls `resolveDependencies` block if it was set.
func resolveProperties(of instance: Any, container: DependencyContainer) throws {
@@ -192,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 {
@@ -246,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])
@@ -317,12 +301,12 @@ private func ~=(lhs: KeyDefinitionPair, rhs: KeyDefinitionPair) -> Bool {
}
/// Returns key-defintion pairs with definitions able to resolve that type (directly or via type forwarding)
/// and which tag matches provided key's tag or is nil.
/// and which tag matches provided key's tag or is nil if strictByTag is false.
/// In the end filters defintions by type of runtime arguments.
func filter(definitions _definitions: [KeyDefinitionPair], byKey key: DefinitionKey, byTypeOfArguments: Bool = false) -> [KeyDefinitionPair] {
func filter(definitions _definitions: [KeyDefinitionPair], byKey key: DefinitionKey, strictByTag: Bool = false, byTypeOfArguments: Bool = false) -> [KeyDefinitionPair] {
let definitions = _definitions
.filter({ $0.key.type == key.type || $0.definition.doesImplements(type: key.type) })
.filter({ $0.key.tag == key.tag || $0.key.tag == nil })
.filter({ $0.key.tag == key.tag || (!strictByTag && $0.key.tag == nil) })
if byTypeOfArguments {
return definitions.filter({ $0.key.typeOfArguments == key.typeOfArguments })
}
+72 -66
View File
@@ -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)
}
@@ -99,19 +106,15 @@ public final class DependencyContainer {
}
}
#if swift(>=3.0)
func threadSafe<T>(_ closure: () throws -> T) rethrows -> T {
guard threadSafe else {
return try closure()
}
lock.lock()
defer { lock.unlock() }
return try closure()
}
#else
func threadSafe<T>(@noescape closure: () throws -> T) rethrows -> T {
lock.lock()
defer { lock.unlock() }
return try closure()
}
#endif
}
@@ -175,12 +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 {
@@ -204,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
@@ -215,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)
@@ -230,7 +240,8 @@ extension DependencyContainer {
context = Context(
key: key,
injectedInType: injectedInType,
injectedInProperty: injectedInProperty
injectedInProperty: injectedInProperty,
inCollaboration: inCollaboration
)
context.logErrors = logErrors ?? currentContext?.logErrors ?? true
@@ -265,8 +276,19 @@ extension DependencyContainer {
public func collaborate(with containers: [DependencyContainer]) {
_collaborators += containers
for container in containers {
container.resolvedInstances.singletonsBox = self.resolvedInstances.singletonsBox
container.resolvedInstances.weakSingletonsBox = self.resolvedInstances.weakSingletonsBox
container._collaborators += [self]
container.resolvedInstances.sharedSingletonsBox = self.resolvedInstances.sharedSingletonsBox
container.resolvedInstances.sharedWeakSingletonsBox = self.resolvedInstances.sharedWeakSingletonsBox
updateCollaborationReferences(between: container, and: self)
}
}
private func updateCollaborationReferences(between container: DependencyContainer, and collaborator: DependencyContainer) {
for container in container._collaborators {
guard container.resolvedInstances.sharedSingletonsBox !== collaborator.resolvedInstances.sharedSingletonsBox else { continue }
container.resolvedInstances.sharedSingletonsBox = collaborator.resolvedInstances.sharedSingletonsBox
container.resolvedInstances.sharedWeakSingletonsBox = collaborator.resolvedInstances.sharedWeakSingletonsBox
updateCollaborationReferences(between: container, and: collaborator)
}
}
@@ -278,11 +300,7 @@ extension DependencyContainer {
//it means that it has been already called to resolve this type,
//so there is probably a cercular reference between containers.
//To break it skip this container
#if swift(>=3.0)
if let context = collaborator.context, context.resolvingType == key.type && context.tag == key.tag { continue }
#else
if let context = collaborator.context where context.resolvingType == key.type && context.tag == key.tag { continue }
#endif
do {
//Pass current container's instances pool to collect instances resolved by collaborator
@@ -292,11 +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)
}
@@ -313,7 +343,6 @@ extension DependencyContainer {
extension DependencyContainer {
#if swift(>=3.0)
/**
Removes definition registered in the container.
@@ -324,18 +353,6 @@ extension DependencyContainer {
public func remove<T, U>(_ definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
_remove(definition: definition, tag: tag)
}
#else
/**
Removes definition registered in the container.
- parameters:
- tag: The tag used to register definition.
- definition: The definition to remove
*/
public func remove<T, U>(definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
_remove(definition: definition, tag: tag)
}
#endif
func _remove<T, U>(definition aDefinition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
let key = DefinitionKey(type: T.self, typeOfArguments: U.self, tag: tag?.dependencyTag)
@@ -350,6 +367,8 @@ extension DependencyContainer {
definitions[key] = nil
resolvedInstances.singletons[key] = nil
resolvedInstances.weakSingletons[key] = nil
resolvedInstances.sharedSingletons[key] = nil
resolvedInstances.sharedWeakSingletons[key] = nil
}
}
@@ -362,6 +381,8 @@ extension DependencyContainer {
definitions.removeAll()
resolvedInstances.singletons.removeAll()
resolvedInstances.weakSingletons.removeAll()
resolvedInstances.sharedSingletons.removeAll()
resolvedInstances.sharedWeakSingletons.removeAll()
bootstrapped = false
}
}
@@ -372,7 +393,6 @@ extension DependencyContainer {
extension DependencyContainer {
#if swift(>=3.0)
/**
Validates container configuration trying to resolve each registered definition one by one.
If definition fails to be resolved without arguments will search provided arguments array
@@ -385,20 +405,6 @@ extension DependencyContainer {
public func validate(_ arguments: Any...) throws {
try _validate(arguments: arguments)
}
#else
/**
Validates container configuration trying to resolve each registered definition one by one.
If definition fails to be resolved without arguments will search provided arguments array
for arguments matched by type and try to resolve this definition using these arguments.
If there are no matching arguments will rethrow original error.
- parameter arguments: Set of arguments to use to resolve registered definitions.
Use a tuple for registered factories that accept several runtime arguments.
*/
public func validate(arguments: Any...) throws {
try _validate(arguments: arguments)
}
#endif
func _validate(arguments _arguments: [Any]) throws {
let arguments = _arguments
@@ -406,11 +412,7 @@ extension DependencyContainer {
do {
//try to resolve key using provided arguments
for argumentsSet in arguments {
#if swift(>=3.0)
guard type(of: argumentsSet) == key.typeOfArguments else { continue }
#else
guard argumentsSet.dynamicType == key.typeOfArguments else { continue }
#endif
guard type(of: argumentsSet) == key.typeOfArguments else { continue }
do {
let _ = try inContext(key:key, injectedInType: nil) {
try self._resolve(key: key, builder: { definition throws -> Any in
@@ -510,13 +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
}
}
}
+5 -9
View File
@@ -22,7 +22,6 @@
// THE SOFTWARE.
//
#if swift(>=3.0)
/**
Errors thrown by `DependencyContainer`'s methods.
@@ -78,19 +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))."
}
}
}
#endif
-116
View File
@@ -1,116 +0,0 @@
//
// Dip
//
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if !swift(>=3.0)
/**
Errors thrown by `DependencyContainer`'s methods.
- seealso: `resolve(tag:)`
*/
public enum DipError: Error, CustomStringConvertible {
/**
Thrown by `resolve(tag:)` if no matching definition was registered in container.
- parameter key: definition key used to lookup matching definition
*/
case DefinitionNotFound(key: DefinitionKey)
/**
Thrown by `resolve(tag:)` if failed to auto-inject required property.
- parameters:
- label: The name of the property
- type: The type of the property
- underlyingError: The error that caused auto-injection to fail
*/
case AutoInjectionFailed(label: String?, type: Any.Type, underlyingError: Error)
/**
Thrown by `resolve(tag:)` if failed to auto-wire a type.
- parameters:
- type: The type that failed to be resolved by auto-wiring
- underlyingError: The error that cause auto-wiring to fail
*/
case AutoWiringFailed(type: Any.Type, underlyingError: Error)
/**
Thrown when auto-wiring type if several definitions with the same number of runtime arguments
are registered for that type.
- parameters:
- type: The type that failed to be resolved by auto-wiring
- definitions: Ambiguous definitions
*/
case AmbiguousDefinitions(type: Any.Type, definitions: [DefinitionType])
/**
Thrown by `resolve(tag:)` if resolved instance does not implemenet resolved type (i.e. when type-forwarding).
- parameters:
- resolved: Resolved instance
- key: Definition key used to resolve instance
*/
case InvalidType(resolved: Any?, key: DefinitionKey)
public var description: String {
switch self {
case let .DefinitionNotFound(key):
return "No definition registered for \(key).\nCheck the tag, type you try to resolve, number, order and types of runtime arguments passed to `resolve()` and match them with registered factories for type \(key.type)."
case let .AutoInjectionFailed(label, type, error):
return "Failed to auto-inject property \"\(label.desc)\" of type \(type). \(error)"
case let .AutoWiringFailed(type, error):
return "Failed to auto-wire type \"\(type)\". \(error)"
case let .AmbiguousDefinitions(type, definitions):
return "Ambiguous definitions for \(type):\n" +
definitions.map({ "\($0)" }).joined(separator: ";\n")
case let .InvalidType(resolved, key):
return "Resolved instance \(resolved ?? "nil") does not implement expected type \(key.type)."
}
}
static func definitionNotFound(key aKey: DefinitionKey) -> DipError {
return DipError.DefinitionNotFound(key: aKey)
}
static func autoInjectionFailed(label aLabel: String?, type: Any.Type, underlyingError: Error) -> DipError {
return DipError.AutoInjectionFailed(label: aLabel, type: type, underlyingError: underlyingError)
}
static func autoWiringFailed(type aType: Any.Type, underlyingError: Error) -> DipError {
return DipError.AutoWiringFailed(type: aType, underlyingError: underlyingError)
}
static func ambiguousDefinitions(type aType: Any.Type, definitions: [DefinitionType]) -> DipError {
return DipError.AmbiguousDefinitions(type: aType, definitions: definitions)
}
static func invalidType(resolved _resolved: Any?, key: DefinitionKey) -> DipError {
return DipError.InvalidType(resolved: _resolved, key: key)
}
}
#endif
+34 -34
View File
@@ -22,41 +22,39 @@
// THE SOFTWARE.
//
#if swift(>=3.0)
extension DependencyContainer {
/**
Registers definition for passed type.
If instance created by factory of definition, passed as a first parameter,
does not implement type passed in a `type` parameter,
container will throw `DipError.DefinitionNotFound` error when trying to resolve that type.
- parameters:
- definition: Definition to register
- type: Type to register definition for
- tag: Optional tag to associate definition with. Default is `nil`.
- returns: New definition registered for passed type.
*/
@discardableResult public func register<T, U, F>(_ definition: Definition<T, U>, type: F.Type, tag: DependencyTagConvertible? = nil) -> Definition<F, U> {
return _register(definition: definition, type: type, tag: tag)
}
/**
Register definiton in the container and associate it with an optional tag.
Will override already registered definition for the same type and factory, associated with the same tag.
- parameters:
- tag: The arbitrary tag to associate this definition with. Pass `nil` to associate with any tag. Default value is `nil`.
- definition: The definition to register in the container.
*/
public func register<T, U>(_ definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
_register(definition: definition, tag: tag)
}
extension DependencyContainer {
/**
Registers definition for passed type.
If instance created by factory of definition, passed as a first parameter,
does not implement type passed in a `type` parameter,
container will throw `DipError.DefinitionNotFound` error when trying to resolve that type.
- parameters:
- definition: Definition to register
- type: Type to register definition for
- tag: Optional tag to associate definition with. Default is `nil`.
- returns: New definition registered for passed type.
*/
@discardableResult public func register<T, U, F>(_ definition: Definition<T, U>, type: F.Type, tag: DependencyTagConvertible? = nil) -> Definition<F, U> {
return _register(definition: definition, type: type, tag: tag)
}
#endif
/**
Register definiton in the container and associate it with an optional tag.
Will override already registered definition for the same type and factory, associated with the same tag.
- parameters:
- tag: The arbitrary tag to associate this definition with. Pass `nil` to associate with any tag. Default value is `nil`.
- definition: The definition to register in the container.
*/
public func register<T, U>(_ definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
_register(definition: definition, tag: tag)
}
}
extension DependencyContainer {
@@ -73,6 +71,8 @@ extension DependencyContainer {
definitions[key] = definition
resolvedInstances.singletons[key] = nil
resolvedInstances.weakSingletons[key] = nil
resolvedInstances.sharedSingletons[key] = nil
resolvedInstances.sharedWeakSingletons[key] = nil
if .eagerSingleton == definition.scope {
bootstrapQueue.append({ _ = try self.resolve(tag: tag) as T })
-59
View File
@@ -1,59 +0,0 @@
//
// Dip
//
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if !swift(>=3.0)
extension DependencyContainer {
/**
Registers definition for passed type.
If instance created by factory of definition, passed as a first parameter,
does not implement type passed in a `type` parameter,
container will throw `DipError.DefinitionNotFound` error when trying to resolve that type.
- parameters:
- definition: Definition to register
- type: Type to register definition for
- tag: Optional tag to associate definition with. Default is `nil`.
- returns: New definition registered for passed type.
*/
public func register<T, U, F>(definition: Definition<T, U>, type: F.Type, tag: DependencyTagConvertible? = nil) -> Definition<F, U> {
return _register(definition: definition, type: type, tag: tag)
}
/**
Register definiton in the container and associate it with an optional tag.
Will override already registered definition for the same type and factory, associated with the same tag.
- parameters:
- tag: The arbitrary tag to associate this definition with. Pass `nil` to associate with any tag. Default value is `nil`.
- definition: The definition to register in the container.
*/
public func register<T, U>(definition: Definition<T, U>, tag: DependencyTagConvertible? = nil) {
_register(definition: definition, tag: tag)
}
}
#endif
+184 -142
View File
@@ -22,106 +22,132 @@
// THE SOFTWARE.
//
#if swift(>=3.0)
extension DependencyContainer {
/**
Resolve an instance of type `T`.
If no matching definition was registered with provided `tag`,
container will lookup definition associated with `nil` tag.
- parameter tag: The arbitrary tag to use to lookup definition.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of type `T`.
**Example**:
```swift
let service = try! container.resolve() as Service
let service = try! container.resolve(tag: "service") as Service
let service: Service = try! container.resolve()
```
- seealso: `register(_:type:tag:factory:)`
*/
public func resolve<T>(tag: DependencyTagConvertible? = nil) throws -> T {
return try resolve(tag: tag) { factory in try factory() }
}
/**
Resolve an instance of requested type. Weakly-typed alternative of `resolve(tag:)`
- warning: This method does not make any type checks, so there is no guaranty that
resulting instance is actually an instance of requested type.
That can happen if you register forwarded type that is not implemented by resolved instance.
- parameters:
- type: Type to resolve
- tag: The arbitrary tag to use to lookup definition.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of requested type.
**Example**:
```swift
let service = try! container.resolve(Service.self) as! Service
let service = try! container.resolve(Service.self, tag: "service") as! Service
```
- seealso: `resolve(tag:)`, `register(_:type:tag:factory:)`
*/
public func resolve(_ type: Any.Type, tag: DependencyTagConvertible? = nil) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory() }
}
/**
Resolve an instance of type `T` using generic builder closure that accepts generic factory and returns created instance.
- parameters:
- tag: The arbitrary tag to use to lookup definition.
- builder: Generic closure that accepts generic factory and returns inctance created by that factory.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of type `T`.
- note: You _should not_ call this method directly, instead call any of other
`resolve(tag:)` or `resolve(tag:withArguments:)` methods.
You _should_ use this method only to resolve dependency with more runtime arguments than
_Dip_ supports (currently it's up to six) like in the following example:
```swift
public func resolve<T, A, B, C, ...>(tag: Tag? = nil, _ arg1: A, _ arg2: B, _ arg3: C, ...) throws -> T {
return try resolve(tag: tag) { factory in factory(arg1, arg2, arg3, ...) }
}
```
Though before you do so you should probably review your design and try to reduce the number of dependencies.
*/
public func resolve<T, U>(tag: DependencyTagConvertible? = nil, builder: ((U) throws -> T) throws -> T) throws -> T {
return try _resolve(tag: tag, builder: builder)
}
/**
Resolve an instance of provided type using builder closure. Weakly-typed alternative of `resolve(tag:builder:)`
- seealso: `resolve(tag:builder:)`
*/
public func resolve<U>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
return try _resolve(type: type, tag: tag, builder: builder)
}
extension DependencyContainer {
/**
Resolve an instance of type `T`.
If no matching definition was registered with provided `tag`,
container will lookup definition associated with `nil` tag.
- parameter tag: The arbitrary tag to use to lookup definition.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of type `T`.
**Example**:
```swift
let service = try! container.resolve() as Service
let service = try! container.resolve(tag: "service") as Service
let service: Service = try! container.resolve()
```
- seealso: `register(_:type:tag:factory:)`
*/
public func resolve<T>(tag: DependencyTagConvertible? = nil) throws -> T {
return try _resolve(tag: tag) { (factory: () throws -> T) in try factory() }
}
#endif
/**
Resolve an instance of requested type. Weakly-typed alternative of `resolve(tag:)`
- warning: This method does not make any type checks, so there is no guaranty that
resulting instance is actually an instance of requested type.
That can happen if you register forwarded type that is not implemented by resolved instance.
- parameters:
- type: Type to resolve
- tag: The arbitrary tag to use to lookup definition.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of requested type.
**Example**:
```swift
let service = try! container.resolve(Service.self) as! Service
let service = try! container.resolve(Service.self, tag: "service") as! Service
```
- seealso: `resolve(tag:)`, `register(_:type:tag:factory:)`
*/
public func resolve(_ type: Any.Type, tag: DependencyTagConvertible? = nil) throws -> Any {
return try resolve(type, tag: tag) { (factory: () throws -> Any) in try factory() }
}
/**
Resolve an instance of type `T` using generic builder closure that accepts generic factory and returns created instance.
- parameters:
- tag: The arbitrary tag to use to lookup definition.
- builder: Generic closure that accepts generic factory and returns inctance created by that factory.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of type `T`.
- note: You _should not_ call this method directly, instead call any of other
`resolve(tag:)` or `resolve(tag:withArguments:)` methods.
You _should_ use this method only to resolve dependency with more runtime arguments than
_Dip_ supports (currently it's up to six) like in the following example:
```swift
public func resolve<T, A, B, C, ...>(tag: Tag? = nil, _ arg1: A, _ arg2: B, _ arg3: C, ...) throws -> T {
return try resolve(tag: tag) { factory in factory(arg1, arg2, arg3, ...) }
}
```
Though before you do so you should probably review your design and try to reduce the number of dependencies.
*/
public func resolve<T, U>(tag: DependencyTagConvertible? = nil, builder: ((U) throws -> T) throws -> T) throws -> T {
return try _resolve(tag: tag, builder: builder)
}
public func resolve<T>(tag: DependencyTagConvertible? = nil, builder: (() throws -> T) throws -> T) throws -> T {
return try _resolve(tag: tag, builder: builder)
}
/**
Resolve an instance of provided type using builder closure. Weakly-typed alternative of `resolve(tag:builder:)`
- seealso: `resolve(tag:builder:)`
*/
public func resolve<U>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
return try _resolve(type: type, tag: tag, builder: builder)
}
public func resolve(_ type: Any.Type, tag: DependencyTagConvertible? = nil, builder: (() throws -> Any) throws -> Any) throws -> Any {
return try _resolve(type: type, tag: tag, builder: builder)
}
}
extension DependencyContainer {
func _resolve<T>(tag aTag: DependencyTagConvertible? = nil, builder: (() throws -> T) throws -> T) throws -> T {
return try resolve(T.self, tag: aTag, builder: { factory in
try withoutActuallyEscaping(factory, do: { (factory) throws -> T in
try builder({ try factory() as! T })
})
}) as! T
}
func _resolve(type aType: Any.Type, tag: DependencyTagConvertible? = nil, builder: (() throws -> Any) throws -> Any) throws -> Any {
let key = DefinitionKey(type: aType, typeOfArguments: Void.self, tag: tag?.dependencyTag)
return try inContext(key:key, injectedInType: context?.resolvingType) {
try self._resolve(key: key, builder: { definition in
try builder { try definition.weakFactory(()) }
})
}
}
func _resolve<T, U>(tag aTag: DependencyTagConvertible? = nil, builder: ((U) throws -> T) throws -> T) throws -> T {
return try resolve(T.self, tag: aTag, builder: { factory in
try builder({ try factory($0) as! T })
try withoutActuallyEscaping(factory, do: { (factory) throws -> T in
try builder({ try factory($0) as! T })
})
}) as! T
}
@@ -138,7 +164,15 @@ extension DependencyContainer {
/// Lookup definition by the key and use it to resolve instance. Fallback to the key with `nil` tag.
func _resolve<T>(key aKey: DefinitionKey, builder: (_Definition) throws -> T) throws -> T {
guard let matching = self.definition(matching: aKey) else {
return try collaboratingResolve(key: aKey, builder: builder) ?? autowire(key: aKey)
do {
return try autowire(key: aKey)
} catch {
if let resolved = collaboratingResolve(key: aKey, builder: builder) {
return resolved
} else {
throw error
}
}
}
let (key, definition) = matching
@@ -149,7 +183,7 @@ extension DependencyContainer {
return previouslyResolved
}
log(level: .Verbose, context)
if let context = context { log(level: .Verbose, context) }
var resolvedInstance = try builder(definition)
/*
@@ -165,7 +199,7 @@ extension DependencyContainer {
That happens because when Optional is casted to Any Swift can not implicitly unwrap it with as operator.
As a workaround we detect boxing here and unwrap it so that we return not a box, but wrapped instance.
*/
if let box = resolvedInstance as? BoxType, let unboxed = box.unboxed as? T {
if let box = resolvedInstance as? BoxType, let unboxedAny = box.unboxed, let unboxed = unboxedAny as? T {
resolvedInstance = unboxed
}
@@ -177,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)")
@@ -193,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
@@ -201,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
}
}
@@ -209,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)
}
@@ -232,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
}
}
}
@@ -275,19 +320,16 @@ class ResolvedInstances {
//MARK: - Resolvable
#if swift(>=3.0)
/// Resolvable protocol provides some extension points for resolving dependencies with property injection.
public protocol Resolvable {
/// This method will be called right after instance is created by the container.
func resolveDependencies(_ container: DependencyContainer)
/// This method will be called when all dependencies of the instance are resolved.
/// When resolving objects graph the last resolved instance will receive this callback first.
func didResolveDependencies()
}
/// Resolvable protocol provides some extension points for resolving dependencies with property injection.
public protocol Resolvable {
/// This method will be called right after instance is created by the container.
func resolveDependencies(_ container: DependencyContainer)
/// This method will be called when all dependencies of the instance are resolved.
/// When resolving objects graph the last resolved instance will receive this callback first.
func didResolveDependencies()
}
extension Resolvable {
func resolveDependencies(_ container: DependencyContainer) {}
func didResolveDependencies() {}
}
#endif
extension Resolvable {
func resolveDependencies(_ container: DependencyContainer) {}
func didResolveDependencies() {}
}
-135
View File
@@ -1,135 +0,0 @@
//
// Dip
//
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if !swift(>=3.0)
extension DependencyContainer {
/**
Resolve an instance of type `T`.
If no matching definition was registered with provided `tag`,
container will lookup definition associated with `nil` tag.
- parameter tag: The arbitrary tag to use to lookup definition.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of type `T`.
**Example**:
```swift
let service = try! container.resolve() as Service
let service = try! container.resolve(tag: "service") as Service
let service: Service = try! container.resolve()
```
- seealso: `register(_:type:tag:factory:)`
*/
public func resolve<T>(tag tag: DependencyTagConvertible? = nil) throws -> T {
return try resolve(tag: tag) { factory in try factory() }
}
/**
Resolve an instance of requested type. Weakly-typed alternative of `resolve(tag:)`
- warning: This method does not make any type checks, so there is no guaranty that
resulting instance is actually an instance of requested type.
That can happen if you register forwarded type that is not implemented by resolved instance.
- parameters:
- type: Type to resolve
- tag: The arbitrary tag to use to lookup definition.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of requested type.
**Example**:
```swift
let service = try! container.resolve(Service.self) as! Service
let service = try! container.resolve(Service.self, tag: "service") as! Service
```
- seealso: `resolve(tag:)`, `register(_:type:tag:factory:)`
*/
public func resolve(type: Any.Type, tag: DependencyTagConvertible? = nil) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory() }
}
/**
Resolve an instance of type `T` using generic builder closure that accepts generic factory and returns created instance.
- parameters:
- tag: The arbitrary tag to use to lookup definition.
- builder: Generic closure that accepts generic factory and returns inctance created by that factory.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
- returns: An instance of type `T`.
- note: You _should not_ call this method directly, instead call any of other
`resolve(tag:)` or `resolve(tag:withArguments:)` methods.
You _should_ use this method only to resolve dependency with more runtime arguments than
_Dip_ supports (currently it's up to six) like in the following example:
```swift
public func resolve<T, A, B, C, ...>(tag: Tag? = nil, _ arg1: A, _ arg2: B, _ arg3: C, ...) throws -> T {
return try resolve(tag: tag) { factory in factory(arg1, arg2, arg3, ...) }
}
```
Though before you do so you should probably review your design and try to reduce the number of dependencies.
*/
public func resolve<T, U>(tag tag: DependencyTagConvertible? = nil, builder: ((U) throws -> T) throws -> T) throws -> T {
return try _resolve(tag: tag, builder: builder)
}
/**
Resolve an instance of provided type using builder closure. Weakly-typed alternative of `resolve(tag:builder:)`
- seealso: `resolve(tag:builder:)`
*/
public func resolve<U>(type: Any.Type, tag: DependencyTagConvertible? = nil, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
return try _resolve(type: type, tag: tag, builder: builder)
}
}
/// Resolvable protocol provides some extension points for resolving dependencies with property injection.
public protocol Resolvable {
/// This method will be called right after instance is created by the container.
func resolveDependencies(container: DependencyContainer)
/// This method will be called when all dependencies of the instance are resolved.
/// When resolving objects graph the last resolved instance will receive this callback first.
func didResolveDependencies()
}
extension Resolvable {
func resolveDependencies(container: DependencyContainer) {}
func didResolveDependencies() {}
}
#endif
+225 -228
View File
@@ -22,235 +22,232 @@
// THE SOFTWARE.
//
#if swift(>=3.0)
extension DependencyContainer {
extension DependencyContainer {
/**
Register factory for type `T` and associate it with an optional tag.
- parameters:
- scope: The scope to use for instance created by the factory. Default value is `Shared`.
- type: Type to register definition for. Default value is return value of factory.
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
- factory: The factory that produces instance of `type`. Will be used to resolve instances of `type`.
- returns: A registered definition.
- note: You should cast the factory return type to the protocol you want to register it for
(unless you want to register concrete type) or provide `type` parameter.
- seealso: `Definition`, `ComponentScope`, `DependencyTagConvertible`
**Example**:
```swift
//Register ServiceImp as Service
container.register { ServiceImp() as Service }
//Register ServiceImp as Service named by "service"
container.register(tag: "service") { ServiceImp() as Service }
//Register unique ServiceImp as Service
container.register(.unique) { ServiceImp() as Service }
//Register ClientImp as Client and resolve it's service dependency
container.register { try ClientImp(service: container.resolve() as Service) as Client }
//Register ServiceImp as concrete type
container.register { ServiceImp() }
container.register(factory: ServiceImp.init)
//Register ServiceImp as Service
container.register(Service.self, factory: ServiceImp.init)
//Register ClientImp as Client
container.register(Client.self, factory: ClientImp.init(service:))
```
*/
@discardableResult public func register<T>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping () throws -> T) -> Definition<T, ()> {
let definition = DefinitionBuilder<T, ()> {
$0.scope = scope
$0.factory = factory
}.build()
register(definition, tag: tag)
return definition
}
/**
Register generic factory and auto-wiring factory and associate it with an optional tag.
- parameters:
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
- scope: The scope to use for instance created by the factory.
- factory: The factory to register.
- numberOfArguments: The number of factory arguments. Will be used on auto-wiring to sort definitions.
- autoWiringFactory: The factory to be used on auto-wiring to resolve component.
- returns: A registered definition.
- note: You _should not_ call this method directly, instead call any of other `register` methods.
You _should_ use this method only to register dependency with more runtime arguments
than _Dip_ supports (currently it's up to six) like in the following example:
```swift
public func register<T, A, B, C, ...>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: Tag? = nil, factory: (A, B, C, ...) throws -> T) -> Definition<T, (A, B, C, ...)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: ...) { container, tag in
try factory(container.resolve(tag: tag), ...)
}
}
```
Though before you do so you should probably review your design and try to reduce number of depnedencies.
*/
public func register<T, U>(scope: ComponentScope, type: T.Type, tag: DependencyTagConvertible?, factory: @escaping (U) throws -> T, numberOfArguments: Int, autoWiringFactory: @escaping (DependencyContainer, Tag?) throws -> T) -> Definition<T, U> {
let definition = DefinitionBuilder<T, U> {
$0.scope = scope
$0.factory = factory
$0.numberOfArguments = numberOfArguments
$0.autoWiringFactory = autoWiringFactory
}.build()
register(definition, tag: tag)
return definition
}
// MARK: 1 Runtime Argument
/**
Register factory that accepts one runtime argument of type `A`. You can use up to six runtime arguments.
- note: You can have several factories with different number or types of arguments registered for same type,
optionally associated with some tags. When container resolves that type it matches the type,
__number__, __types__ and __order__ of runtime arguments and optional tag that you pass to `resolve(tag:arguments:)` method.
- parameters:
/**
Register factory for type `T` and associate it with an optional tag.
- parameters:
- scope: The scope to use for instance created by the factory. Default value is `Shared`.
- type: Type to register definition for. Default value is return value of factory.
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
- scope: The scope to use for this component. Default value is `Shared`.
- factory: The factory to register.
- seealso: `register(_:type:tag:factory:)`
*/
@discardableResult public func register<T, A>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A) throws -> T) -> Definition<T, A> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 1) { container, tag in try factory(container.resolve(tag: tag)) }
}
/**
Resolve type `T` using one runtime argument.
- note: When resolving a type container will first try to use definition
that exactly matches types of arguments that you pass to resolve method.
If it fails or no such definition is found container will try to _auto-wire_ component.
For that it will iterate through all the definitions registered for that type
which factories accept any number of runtime arguments and are tagged with the same tag,
passed to `resolve` method, or with no tag. Container will try to use these definitions
to resolve a component one by one until one of them succeeds, starting with tagged definitions
in order of decreasing their's factories number of arguments. If none of them succeds it will
throw an error. If it finds two definitions with the same number of arguments - it will throw
an error.
- parameters:
- tag: The arbitrary tag to lookup registered definition.
- arg1: The first argument to pass to the definition's factory.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`
- returns: An instance of type `T`.
- seealso: `register(_:type:tag:factory:)`, `resolve(tag:builder:)`
*/
public func resolve<T, A>(tag: DependencyTagConvertible? = nil, arguments arg1: A) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory(arg1) }
}
// MARK: 2 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B) throws -> T) -> Definition<T, (A, B)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 2) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2)) }
}
// MARK: 3 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C) throws -> T) -> Definition<T, (A, B, C)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 3) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3)) }
}
// MARK: 4 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C, D>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C, D) throws -> T) -> Definition<T, (A, B, C, D)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 4) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4) }
}
/// - seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C, D>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4)) }
}
// MARK: 5 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C, D, E>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C, D, E) throws -> T) -> Definition<T, (A, B, C, D, E)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 5) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D, E>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4, arg5) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C, D, E>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5)) }
}
// MARK: 6 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C, D, E, F>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C, D, E, F) throws -> T) -> Definition<T, (A, B, C, D, E, F)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 6) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D, E, F>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4, arg5, arg6) }
}
/// - seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C, D, E, F>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5, arg6)) }
}
- factory: The factory that produces instance of `type`. Will be used to resolve instances of `type`.
- returns: A registered definition.
- note: You should cast the factory return type to the protocol you want to register it for
(unless you want to register concrete type) or provide `type` parameter.
- seealso: `Definition`, `ComponentScope`, `DependencyTagConvertible`
**Example**:
```swift
//Register ServiceImp as Service
container.register { ServiceImp() as Service }
//Register ServiceImp as Service named by "service"
container.register(tag: "service") { ServiceImp() as Service }
//Register unique ServiceImp as Service
container.register(.unique) { ServiceImp() as Service }
//Register ClientImp as Client and resolve it's service dependency
container.register { try ClientImp(service: container.resolve() as Service) as Client }
//Register ServiceImp as concrete type
container.register { ServiceImp() }
container.register(factory: ServiceImp.init)
//Register ServiceImp as Service
container.register(Service.self, factory: ServiceImp.init)
//Register ClientImp as Client
container.register(Client.self, factory: ClientImp.init(service:))
```
*/
@discardableResult public func register<T>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (()) throws -> T) -> Definition<T, ()> {
let definition = DefinitionBuilder<T, ()> {
$0.scope = scope
$0.factory = factory
}.build()
register(definition, tag: tag)
return definition
}
#endif
/**
Register generic factory and auto-wiring factory and associate it with an optional tag.
- parameters:
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
- scope: The scope to use for instance created by the factory.
- factory: The factory to register.
- numberOfArguments: The number of factory arguments. Will be used on auto-wiring to sort definitions.
- autoWiringFactory: The factory to be used on auto-wiring to resolve component.
- returns: A registered definition.
- note: You _should not_ call this method directly, instead call any of other `register` methods.
You _should_ use this method only to register dependency with more runtime arguments
than _Dip_ supports (currently it's up to six) like in the following example:
```swift
public func register<T, A, B, C, ...>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: Tag? = nil, factory: (A, B, C, ...) throws -> T) -> Definition<T, (A, B, C, ...)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: ...) { container, tag in
try factory(container.resolve(tag: tag), ...)
}
}
```
Though before you do so you should probably review your design and try to reduce number of depnedencies.
*/
public func register<T, U>(scope: ComponentScope, type: T.Type, tag: DependencyTagConvertible?, factory: @escaping (U) throws -> T, numberOfArguments: Int, autoWiringFactory: @escaping (DependencyContainer, Tag?) throws -> T) -> Definition<T, U> {
let definition = DefinitionBuilder<T, U> {
$0.scope = scope
$0.factory = factory
$0.numberOfArguments = numberOfArguments
$0.autoWiringFactory = autoWiringFactory
}.build()
register(definition, tag: tag)
return definition
}
// MARK: 1 Runtime Argument
/**
Register factory that accepts one runtime argument of type `A`. You can use up to six runtime arguments.
- note: You can have several factories with different number or types of arguments registered for same type,
optionally associated with some tags. When container resolves that type it matches the type,
__number__, __types__ and __order__ of runtime arguments and optional tag that you pass to `resolve(tag:arguments:)` method.
- parameters:
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
- scope: The scope to use for this component. Default value is `Shared`.
- factory: The factory to register.
- seealso: `register(_:type:tag:factory:)`
*/
@discardableResult public func register<T, A>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A)) throws -> T) -> Definition<T, A> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 1) { container, tag in try factory(container.resolve(tag: tag)) }
}
/**
Resolve type `T` using one runtime argument.
- note: When resolving a type container will first try to use definition
that exactly matches types of arguments that you pass to resolve method.
If it fails or no such definition is found container will try to _auto-wire_ component.
For that it will iterate through all the definitions registered for that type
which factories accept any number of runtime arguments and are tagged with the same tag,
passed to `resolve` method, or with no tag. Container will try to use these definitions
to resolve a component one by one until one of them succeeds, starting with tagged definitions
in order of decreasing their's factories number of arguments. If none of them succeds it will
throw an error. If it finds two definitions with the same number of arguments - it will throw
an error.
- parameters:
- tag: The arbitrary tag to lookup registered definition.
- arg1: The first argument to pass to the definition's factory.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`
- returns: An instance of type `T`.
- seealso: `register(_:type:tag:factory:)`, `resolve(tag:builder:)`
*/
public func resolve<T, A>(tag: DependencyTagConvertible? = nil, arguments arg1: A) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory(arg1) }
}
// MARK: 2 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A, B)
) throws -> T) -> Definition<T, (A, B)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 2) { container, tag in try factory((container.resolve(tag: tag), container.resolve(tag: tag))) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B) throws -> T {
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2)) } as! T
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2)) }
}
// MARK: 3 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A, B, C)) throws -> T) -> Definition<T, (A, B, C)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 3) { container, tag in try factory((container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag))) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C) throws -> T {
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3)) } as! T
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3)) }
}
// MARK: 4 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C, D>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A, B, C, D)) throws -> T) -> Definition<T, (A, B, C, D)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 4) { container, tag in try factory((container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag))) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D) throws -> T {
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4)) } as! T
}
/// - seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C, D>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4)) }
}
// MARK: 5 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C, D, E>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A, B, C, D, E)) throws -> T) -> Definition<T, (A, B, C, D, E)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 5) { container, tag in try factory((container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag))) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D, E>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E) throws -> T {
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5)) } as! T
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C, D, E>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5)) }
}
// MARK: 6 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C, D, E, F>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A, B, C, D, E, F)) throws -> T) -> Definition<T, (A, B, C, D, E, F)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 6) { container, tag in try factory((container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag))) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D, E, F>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F) throws -> T {
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5, arg6)) } as! T
}
/// - seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C, D, E, F>(_ type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5, arg6)) }
}
}
-256
View File
@@ -1,256 +0,0 @@
//
// Dip
//
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if !swift(>=3.0)
extension DependencyContainer {
/**
Register factory for type `T` and associate it with an optional tag.
- parameters:
- scope: The scope to use for instance created by the factory. Default value is `Shared`.
- type: Type to register definition for. Default value is return value of factory.
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
- factory: The factory that produces instance of `type`. Will be used to resolve instances of `type`.
- returns: A registered definition.
- note: You should cast the factory return type to the protocol you want to register it for
(unless you want to register concrete type) or provide `type` parameter.
- seealso: `Definition`, `ComponentScope`, `DependencyTagConvertible`
**Example**:
```swift
//Register ServiceImp as Service
container.register { ServiceImp() as Service }
//Register ServiceImp as Service named by "service"
container.register(tag: "service") { ServiceImp() as Service }
//Register unique ServiceImp as Service
container.register(.unique) { ServiceImp() as Service }
//Register ClientImp as Client and resolve it's service dependency
container.register { try ClientImp(service: container.resolve() as Service) as Client }
//Register ServiceImp as concrete type
container.register { ServiceImp() }
container.register(factory: ServiceImp.init)
//Register ServiceImp as Service
container.register(Service.self, factory: ServiceImp.init)
//Register ClientImp as Client
container.register(Client.self, factory: ClientImp.init(service:))
```
*/
public func register<T>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: () throws -> T) -> Definition<T, ()> {
let definition = DefinitionBuilder<T, ()> {
$0.scope = scope
$0.factory = factory
}.build()
register(definition, tag: tag)
return definition
}
/**
Register generic factory and auto-wiring factory and associate it with an optional tag.
- parameters:
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
- scope: The scope to use for instance created by the factory.
- factory: The factory to register.
- numberOfArguments: The number of factory arguments. Will be used on auto-wiring to sort definitions.
- autoWiringFactory: The factory to be used on auto-wiring to resolve component.
- returns: A registered definition.
- note: You _should not_ call this method directly, instead call any of other `register` methods.
You _should_ use this method only to register dependency with more runtime arguments
than _Dip_ supports (currently it's up to six) like in the following example:
```swift
public func register<T, A, B, C, ...>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: Tag? = nil, factory: (A, B, C, ...) throws -> T) -> Definition<T, (A, B, C, ...)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: ...) { container, tag in
try factory(container.resolve(tag: tag), ...)
}
}
```
Though before you do so you should probably review your design and try to reduce number of depnedencies.
*/
public func register<T, U>(scope: ComponentScope, type: T.Type, tag: DependencyTagConvertible?, factory: (U) throws -> T, numberOfArguments: Int, autoWiringFactory: (DependencyContainer, Tag?) throws -> T) -> Definition<T, U> {
let definition = DefinitionBuilder<T, U> {
$0.scope = scope
$0.factory = factory
$0.numberOfArguments = numberOfArguments
$0.autoWiringFactory = autoWiringFactory
}.build()
register(definition, tag: tag)
return definition
}
// MARK: 1 Runtime Argument
/**
Register factory that accepts one runtime argument of type `A`. You can use up to six runtime arguments.
- note: You can have several factories with different number or types of arguments registered for same type,
optionally associated with some tags. When container resolves that type it matches the type,
__number__, __types__ and __order__ of runtime arguments and optional tag that you pass to `resolve(tag:arguments:)` method.
- parameters:
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
- scope: The scope to use for this component. Default value is `Shared`.
- factory: The factory to register.
- seealso: `register(_:type:tag:factory:)`
*/
public func register<T, A>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A) throws -> T) -> Definition<T, A> {
return register(scope, type: type, tag: tag, factory: factory, numberOfArguments: 1) { container, tag in try factory(container.resolve(tag: tag)) }
}
/**
Resolve type `T` using one runtime argument.
- note: When resolving a type container will first try to use definition
that exactly matches types of arguments that you pass to resolve method.
If it fails or no such definition is found container will try to _auto-wire_ component.
For that it will iterate through all the definitions registered for that type
which factories accept any number of runtime arguments and are tagged with the same tag,
passed to `resolve` method, or with no tag. Container will try to use these definitions
to resolve a component one by one until one of them succeeds, starting with tagged definitions
in order of decreasing their's factories number of arguments. If none of them succeds it will
throw an error. If it finds two definitions with the same number of arguments - it will throw
an error.
- parameters:
- tag: The arbitrary tag to lookup registered definition.
- arg1: The first argument to pass to the definition's factory.
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`
- returns: An instance of type `T`.
- seealso: `register(_:tag:factory:)`, `resolve(tag:builder:)`
*/
public func resolve<T, A>(tag tag: DependencyTagConvertible? = nil, arguments arg1: A) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A>(type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory(arg1) }
}
// MARK: 2 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
public func register<T, A, B>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A, B) throws -> T) -> Definition<T, (A, B)> {
return register(scope, type: type, tag: tag, factory: factory, numberOfArguments: 2) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B>(tag tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B>(type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2)) }
}
// MARK: 3 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
public func register<T, A, B, C>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A, B, C) throws -> T) -> Definition<T, (A, B, C)> {
return register(scope, type: type, tag: tag, factory: factory, numberOfArguments: 3) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C>(tag tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C>(type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3)) }
}
// MARK: 4 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
public func register<T, A, B, C, D>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A, B, C, D) throws -> T) -> Definition<T, (A, B, C, D)> {
return register(scope, type: type, tag: tag, factory: factory, numberOfArguments: 4) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D>(tag tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4) }
}
/// - seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C, D>(type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4)) }
}
// MARK: 5 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
public func register<T, A, B, C, D, E>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A, B, C, D, E) throws -> T) -> Definition<T, (A, B, C, D, E)> {
return register(scope, type: type, tag: tag, factory: factory, numberOfArguments: 5) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D, E>(tag tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4, arg5) }
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C, D, E>(type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5)) }
}
// MARK: 6 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
public func register<T, A, B, C, D, E, F>(scope: ComponentScope = .Shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: (A, B, C, D, E, F) throws -> T) -> Definition<T, (A, B, C, D, E, F)> {
return register(scope, type: type, tag: tag, factory: factory, numberOfArguments: 6) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D, E, F>(tag tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4, arg5, arg6) }
}
/// - seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
public func resolve<A, B, C, D, E, F>(type: Any.Type, tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5, arg6)) }
}
}
#endif
+245
View File
@@ -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))
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
+1 -5
View File
@@ -27,8 +27,6 @@ protocol TypeForwardingDefinition: DefinitionType {
func doesImplements(type aType: Any.Type) -> Bool
}
#if swift(>=3.0)
extension Definition {
/**
@@ -84,14 +82,12 @@ extension Definition {
}
///Registers definition for types passed as parameters
@discardableResult public func implements<A, B, C, D>(_ a: A.Type, _ b: B.Type, c: C.Type, d: D.Type) -> Definition {
@discardableResult public func implements<A, B, C, D>(_ a: A.Type, _ b: B.Type, _ c: C.Type, _ d: D.Type) -> Definition {
return implements(a).implements(b).implements(c).implements(d)
}
}
#endif
extension DependencyContainer {
func _register<T, U, F>(definition aDefinition: Definition<T, U>, type: F.Type, tag: DependencyTagConvertible? = nil) -> Definition<F, U> {
-88
View File
@@ -1,88 +0,0 @@
//
// Dip
//
// Copyright (c) 2015 Olivier Halligon <olivier@halligon.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if !swift(>=3.0)
extension Definition {
/**
Registers definition for passed type.
If instance created by factory of definition on which method is called
does not implement type passed in a `type` parameter,
container will throw `DipError.DefinitionNotFound` error when trying to resolve that type.
- parameters:
- type: Type to register definition for
- tag: Optional tag to associate definition with. Default is `nil`.
- returns: definition on which `implements` was called
*/
public func implements<F>(type: F.Type, tag: DependencyTagConvertible? = nil) -> Definition {
precondition(container != nil, "Definition should be registered in the container.")
container!.register(self, type: type, tag: tag)
return self
}
/**
Registers definition for passed type.
If instance created by factory of definition on which method is called
does not implement type passed in a `type` parameter,
container will throw `DipError.DefinitionNotFound` error when trying to resolve that type.
- parameters:
- type: Type to register definition for
- tag: Optional tag to associate definition with. Default is `nil`.
- resolvingProperties: Optional block to be called to resolve instance property dependencies
- returns: definition on which `implements` was called
*/
public func implements<F>(type: F.Type, tag: DependencyTagConvertible? = nil, resolvingProperties: (DependencyContainer, F) throws -> ()) -> Definition {
precondition(container != nil, "Definition should be registered in the container.")
let forwardDefinition = container!.register(self, type: type, tag: tag)
forwardDefinition.resolvingProperties(resolvingProperties)
return self
}
///Registers definition for types passed as parameters
public func implements<A, B>(a: A.Type, _ b: B.Type) -> Definition {
return implements(a).implements(b)
}
///Registers definition for types passed as parameters
public func implements<A, B, C>(a: A.Type, _ b: B.Type, _ c: C.Type) -> Definition {
return implements(a).implements(b).implements(c)
}
///Registers definition for types passed as parameters
public func implements<A, B, C, D>(a: A.Type, _ b: B.Type, c: C.Type, d: D.Type) -> Definition {
return implements(a).implements(b).implements(c).implements(d)
}
}
#endif
+12 -15
View File
@@ -30,9 +30,11 @@ public enum LogLevel: Int {
public var logLevel: LogLevel = .Errors
public var logger: (LogLevel, Any) -> Void = { print($1) }
func log(level logLevel: LogLevel, _ message: Any) {
guard logLevel.rawValue <= Dip.logLevel.rawValue else { return }
print(message)
logger(logLevel, message)
}
///Internal protocol used to unwrap optional values.
@@ -46,11 +48,6 @@ extension Optional: BoxType {
}
}
extension ImplicitlyUnwrappedOptional: BoxType {
var unboxed: Any? {
return self ?? nil
}
}
class Box<T> {
var unboxed: T
@@ -59,6 +56,13 @@ class Box<T> {
}
}
class NullableBox<T> {
var unboxed: T?
init(_ value: T?) {
self.unboxed = value
}
}
protocol WeakBoxType {
var unboxed: AnyObject? { get }
}
@@ -69,15 +73,8 @@ class WeakBox<T>: WeakBoxType {
return unboxed as? T
}
init(_ value: T) {
#if !_runtime(_ObjC) || !swift(>=3.0)
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
}
}
+160 -32
View File
@@ -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)
}
}
+61 -55
View File
@@ -50,28 +50,6 @@ class AutoWiringTests: XCTestCase {
let container = DependencyContainer()
static var allTests = {
return [
("testThatItCanResolveWithAutoWiring", testThatItCanResolveWithAutoWiring),
("testThatItUsesAutoWireFactoryWithMostNumberOfArguments", testThatItUsesAutoWireFactoryWithMostNumberOfArguments),
("testThatItThrowsAmbiguityErrorWhenUsingAutoWire", testThatItThrowsAmbiguityErrorWhenUsingAutoWire),
("testThatItFirstTriesToUseTaggedFactoriesWhenUsingAutoWire", testThatItFirstTriesToUseTaggedFactoriesWhenUsingAutoWire),
("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()
}
@@ -110,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
}
@@ -136,17 +114,15 @@ 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
}
}
}
func testThatItFirstTriesToUseTaggedFactoriesWhenUsingAutoWire() {
func testThatItPrefersTaggedFactoryWithDifferentNumberOfArgumentsWhenUsingAutoWire() {
//given
//1 arg
@@ -162,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
}
@@ -176,12 +152,37 @@ class AutoWiringTests: XCTestCase {
XCTAssertTrue(taggedFactoryWithMostNumberOfArgumentsCalled)
}
func testThatItPrefersTaggedFactoryWithDifferentTypesOfArgumentsWhenUsingAutoWire() {
//given
//1 arg
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
//2 args
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
//1 arg tagged
var taggedFactoryCalled = false
container.register(tag: "tag") { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }.resolvingProperties { _,_ in
taggedFactoryCalled = true
}
container.register() { ServiceImp1() as Service }
container.register { ServiceImp2() }
//when
let _ = try! container.resolve(tag: "tag") as AutoWiredClient
//then
XCTAssertTrue(taggedFactoryCalled)
}
func testThatItFallbackToNotTaggedFactoryWhenUsingAutoWire() {
//given
//1 arg
var notTaggedFactoryWithMostNumberOfArgumentsCalled = false
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }.resolvingProperties { _ in
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }.resolvingProperties { _,_ in
notTaggedFactoryWithMostNumberOfArgumentsCalled = true
}
@@ -206,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() {
@@ -232,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() }
@@ -255,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() {
@@ -280,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() {
@@ -303,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() {
@@ -326,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() {
@@ -437,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)
}
+5 -29
View File
@@ -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() {
+15 -29
View File
@@ -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)
}
-13
View File
@@ -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 }))
}
}
+263 -116
View File
@@ -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
}
}
}
@@ -658,20 +619,22 @@ extension DipTests {
//given
let collaborator = DependencyContainer()
collaborator.register { ResolvableService() as Service }
container.register { "something" }
//when
container.collaborate(with: collaborator)
//then
AssertNoThrow(expression: try container.resolve() as Service)
AssertNoThrow(expression: try container.resolve(Service.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() {
let collaborator = DependencyContainer()
collaborator.collaborate(with: collaborator)
XCTAssertTrue(collaborator._collaborators.isEmpty, "Container should not collaborate with itself")
}
func testThatCollaboratingContainersAreWeakReferences() {
@@ -730,4 +693,188 @@ extension DipTests {
XCTAssertTrue(client?.server === (client as? ClientImp)?.anotherServer)
}
func testThatCollaborationReferencesAreRecursivelyUpdate() {
let container = DependencyContainer()
container.register(.singleton){ ResolvableService() as Service }
//when
let collaborator1 = DependencyContainer()
let collaborator2 = DependencyContainer()
let collaborator3 = DependencyContainer()
let collaborator4 = DependencyContainer()
collaborator1.collaborate(with: container)
XCTAssertTrue(collaborator1.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
collaborator2.collaborate(with: container)
XCTAssertTrue(collaborator2.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
collaborator3.collaborate(with: collaborator1)
XCTAssertTrue(collaborator3.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
collaborator4.collaborate(with: collaborator2)
XCTAssertTrue(collaborator4.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
let service1 = try! collaborator1.resolve() as Service
let service2 = try! collaborator2.resolve() as Service
let service3 = try! collaborator3.resolve() as Service
let service4 = try! collaborator4.resolve() as Service
let serviceRoot = try! container.resolve() as Service
XCTAssertTrue(service1 === service2)
XCTAssertTrue(service1 === service3)
XCTAssertTrue(service1 === service4)
XCTAssertTrue(service1 === serviceRoot)
XCTAssertTrue(service2 === serviceRoot)
XCTAssertTrue(service3 === serviceRoot)
XCTAssertTrue(service4 === serviceRoot)
}
class RootService {}
class ServiceClient {
let name: String
let service: RootService
init(name: String, service: RootService) {
self.name = name
self.service = service
}
}
func testThatContainersShareTheirSingletonsOnlyWithCollaborators() {
let container = DependencyContainer()
container.register(.singleton) { RootService() }
let collaborator1 = DependencyContainer()
collaborator1.register(.singleton) {
ServiceClient(name: "1", service: $0)
}
let collaborator2 = DependencyContainer()
collaborator2.register(.singleton) {
ServiceClient(name: "2", service: $0)
}
collaborator1.collaborate(with: container)
collaborator2.collaborate(with: container)
let client2 = try! collaborator2.resolve() as ServiceClient
let client1 = try! collaborator1.resolve() as ServiceClient
XCTAssertEqual(client1.name, "1")
XCTAssertEqual(client2.name, "2")
XCTAssertTrue(client1.service === client2.service)
}
func testThatContainerAutowireBeforeCollaboration() {
let container = DependencyContainer()
container.register(.singleton) { RootService() }
let collaborator1 = DependencyContainer()
collaborator1.register(.singleton) {
ServiceClient(name: "1", service: $0)
}
let collaborator2 = DependencyContainer()
collaborator2.register(.singleton) {
ServiceClient(name: "2", service: $0)
}
collaborator1.collaborate(with: container, collaborator2)
collaborator2.collaborate(with: container, collaborator1)
let client2 = try! collaborator2.resolve() as ServiceClient
let client1 = try! collaborator1.resolve() as ServiceClient
XCTAssertEqual(client1.name, "1")
XCTAssertEqual(client2.name, "2")
XCTAssertTrue(client1.service === client2.service)
}
}
class Manager {}
class AnotherManager {}
class Object {
let manager: Manager?
init(with container: DependencyContainer) {
self.manager = try? container.resolve()
}
}
class Owner {
var manager: Manager?
}
extension DipTests {
func testThatItCanHandleSeparateContainersAndTheirCollaboration() {
let container = self.container
let anotherContainer = DependencyContainer()
anotherContainer.register { Object(with: anotherContainer) }
container.collaborate(with: anotherContainer)
container
.register { Owner() }
.resolvingProperties { $1.manager = try $0.resolve() }
container.register(.singleton) { AnotherManager() }
container.register(.singleton) { Manager() }
let manager: Manager? = try? container.resolve()
let another: AnotherManager? = try? container.resolve()
var owner: Owner? = try? container.resolve(arguments: 1, "")
let object: Object? = try? container.resolve()
owner = try? container.resolve()
let nonNilValues: [Any?] = [another, manager, owner, object, object?.manager]
nonNilValues.forEach { XCTAssertNotNil($0) }
XCTAssertTrue(
owner?.manager
.flatMap { value in
manager.flatMap { $0 === value }
}
?? false
)
}
}
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 {
}
}
}
+252
View File
@@ -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()
}
+4 -92
View File
@@ -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
+71 -31
View File
@@ -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
}
}
+1 -36
View File
@@ -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
-14
View File
@@ -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)
])
+202
View File
@@ -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