Compare commits

...

60 Commits

Author SHA1 Message Date
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
44 changed files with 1250 additions and 426 deletions
+1 -1
View File
@@ -1 +1 @@
3.1
4.2
+7 -24
View File
@@ -3,21 +3,18 @@ matrix:
- os: linux
include:
- script:
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.1' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk macosx -destination 'platform=macOS,arch=x86_64' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV 1080p,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
# disable running watchos until https://github.com/travis-ci/travis-ci/issues/7580 is fixed
#- set -o pipefail && xcodebuild -workspace Dip.xcworkspace -scheme Dip -sdk watchsimulator -destination 'platform=watchOS Simulator,name=Apple Watch - 38mm,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty - c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme DipSampleApp -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=10.1' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- pod spec lint --allow-warnings
- carthage build --no-skip-current
- swift package clean && swift build && swift test
os: osx
osx_image: xcode8.3
osx_image: xcode10
language: objective-c
before_install:
- gem install cocoapods --version 1.1.0.rc.2 --no-document
- gem install cocoapods --version 1.6.0.beta.1 --no-document
- script:
- swift build --clean && swift build && swift test
- swift package clean && swift build && swift test
os: linux
dist: trusty
sudo: required
@@ -25,22 +22,8 @@ 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
- tar xzf $SWIFT_VERSION-ubuntu14.04.tar.gz
- export PATH="${PWD}/${SWIFT_VERSION}-ubuntu14.04/usr/bin:${PATH}"
- cd Dip
- script:
- swift build --clean && swift build && swift test
os: linux
dist: trusty
sudo: required
language: generic
before_install:
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
- cd ..
- export SWIFT_VERSION=swift-3.1-RELEASE
- wget https://swift.org/builds/swift-3.1-release/ubuntu1404/$SWIFT_VERSION/$SWIFT_VERSION-ubuntu14.04.tar.gz
- export SWIFT_VERSION=swift-4.2-RELEASE
- wget https://swift.org/builds/swift-4.2-release/ubuntu1404/$SWIFT_VERSION/$SWIFT_VERSION-ubuntu14.04.tar.gz
- tar xzf $SWIFT_VERSION-ubuntu14.04.tar.gz
- export PATH="${PWD}/${SWIFT_VERSION}-ubuntu14.04/usr/bin:${PATH}"
- cd Dip
+20
View File
@@ -1,5 +1,25 @@
# CHANGELOG
## 7.0.0
* Swift 4.2 support.
* Fixed some issues when reusing instances previously resolved as optionals.
* Dip-UI is now part of Dip.
## 6.1
* Swift 4.1 support.
* Fixed crashes resolving singletons using collaborating containers.
[#179](https://github.com/AliSoftware/Dip/pull/179), [@trimmurrti](https://github.com/trimmurrti)
[#182](https://github.com/AliSoftware/Dip/pull/182), [@tapsandswipes](https://github.com/tapsandswipes)
## 6.0
* Swift 4 support
* Fixed unneeded reuse of singletons in collaborating containers.
Containers now first attempt to autowire components and fallback to collaboration when it fails.
[#169](https://github.com/AliSoftware/Dip/issues/169), [@ilyapuchka](https://github.com/ilyapuchka)
## 5.1
* Dropped Swift 2.3 support.
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Dip"
s.version = "5.1"
s.version = "7.0.0"
s.summary = "Dependency Injection for Swift made easy."
s.description = <<-DESC
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
+66 -5
View File
@@ -31,6 +31,8 @@
09FC480F1DAA9CAF00566AA8 /* Register.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC480C1DAA9CAF00566AA8 /* Register.swift */; };
09FC48181DAAA53100566AA8 /* DipError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC48161DAAA53100566AA8 /* DipError.swift */; };
09FC481E1DAAA8F900566AA8 /* ComponentScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FC481C1DAAA8F900566AA8 /* ComponentScope.swift */; };
63937A6A21524C0B00AEE75A /* StoryboardInstantiatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63937A6921524C0B00AEE75A /* StoryboardInstantiatable.swift */; };
63937A6F21524DA300AEE75A /* DipUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63937A6B21524DA200AEE75A /* DipUITests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -71,6 +73,11 @@
09FC480C1DAA9CAF00566AA8 /* Register.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Register.swift; path = ../../Sources/Register.swift; sourceTree = "<group>"; };
09FC48161DAAA53100566AA8 /* DipError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DipError.swift; path = ../../Sources/DipError.swift; sourceTree = "<group>"; };
09FC481C1DAAA8F900566AA8 /* ComponentScope.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComponentScope.swift; path = ../../Sources/ComponentScope.swift; sourceTree = "<group>"; };
63937A6921524C0B00AEE75A /* StoryboardInstantiatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StoryboardInstantiatable.swift; path = ../../Sources/StoryboardInstantiatable.swift; sourceTree = "<group>"; };
63937A6B21524DA200AEE75A /* DipUITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DipUITests.swift; path = ../../Tests/DipTests/DipUITests.swift; sourceTree = "<group>"; };
63937A6C21524DA200AEE75A /* NSStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NSStoryboard.storyboard; sourceTree = "<group>"; };
63937A6D21524DA300AEE75A /* TVStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = TVStoryboard.storyboard; sourceTree = "<group>"; };
63937A6E21524DA300AEE75A /* UIStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UIStoryboard.storyboard; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -108,6 +115,7 @@
095F829B1D043B41008CD706 /* TypeForwarding.swift */,
0982AF0B1C5183A000B62463 /* Utils.swift */,
09871B401DAA6BF300B40B91 /* Compatibility.swift */,
63937A6921524C0B00AEE75A /* StoryboardInstantiatable.swift */,
0919F4CB1C16417000DC3B10 /* Info.plist */,
);
path = Dip;
@@ -125,6 +133,10 @@
09BD350A1D84E30D00B33E53 /* RuntimeArgumentsTests.swift */,
09BD350B1D84E30D00B33E53 /* ThreadSafetyTests.swift */,
09BD350C1D84E30D00B33E53 /* TypeForwardingTests.swift */,
63937A6B21524DA200AEE75A /* DipUITests.swift */,
63937A6C21524DA200AEE75A /* NSStoryboard.storyboard */,
63937A6D21524DA300AEE75A /* TVStoryboard.storyboard */,
63937A6E21524DA300AEE75A /* UIStoryboard.storyboard */,
09BD350D1D84E30D00B33E53 /* Utils.swift */,
0919F4D11C16417000DC3B10 /* Info.plist */,
);
@@ -189,6 +201,7 @@
buildPhases = (
0903B35D1C161543002241C1 /* Sources */,
0903B35E1C161543002241C1 /* Frameworks */,
63937A7721524E3B00AEE75A /* ShellScript */,
0903B35F1C161543002241C1 /* Resources */,
);
buildRules = (
@@ -208,7 +221,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0800;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = AliSoftware;
TargetAttributes = {
0903B3571C161543002241C1 = {
@@ -256,6 +269,26 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
63937A7721524E3B00AEE75A /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"${SRCROOT}/DipTests/${STORYBOARD_NAME_PREFIX}Storyboard.storyboard\"\nibtool --compilation-directory \"${TARGET_TEMP_DIR}\" \"${SRCROOT}/DipTests/${STORYBOARD_NAME_PREFIX}Storyboard.storyboard\"\nibtool --link \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\" \"${TARGET_TEMP_DIR}/${STORYBOARD_NAME_PREFIX}Storyboard.storyboardc\"\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
0903B3531C161543002241C1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
@@ -265,6 +298,7 @@
0982AF0C1C5183A000B62463 /* Utils.swift in Sources */,
0919F4D51C16417B00DC3B10 /* Definition.swift in Sources */,
09FC481E1DAAA8F900566AA8 /* ComponentScope.swift in Sources */,
63937A6A21524C0B00AEE75A /* StoryboardInstantiatable.swift in Sources */,
09B036001C5D2B83001EA5B7 /* AutoWiring.swift in Sources */,
0919F4D41C16417B00DC3B10 /* Dip.swift in Sources */,
09FC480F1DAA9CAF00566AA8 /* Register.swift in Sources */,
@@ -282,6 +316,7 @@
files = (
09BD35141D84E30D00B33E53 /* RuntimeArgumentsTests.swift in Sources */,
09BD35151D84E30D00B33E53 /* ThreadSafetyTests.swift in Sources */,
63937A6F21524DA300AEE75A /* DipUITests.swift in Sources */,
09BD35121D84E30D00B33E53 /* DefinitionTests.swift in Sources */,
09BD350F1D84E30D00B33E53 /* AutoWiringTests.swift in Sources */,
09BD35111D84E30D00B33E53 /* ContextTests.swift in Sources */,
@@ -325,6 +360,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.Dip;
PRODUCT_NAME = Dip;
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.2;
};
name = Debug;
};
@@ -344,6 +380,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.Dip;
PRODUCT_NAME = Dip;
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.2;
};
name = Release;
};
@@ -359,7 +396,13 @@
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipTests;
PRODUCT_NAME = "$(TARGET_NAME)";
STORYBOARD_NAME_PREFIX = NS;
"STORYBOARD_NAME_PREFIX[sdk=appletvos*]" = TV;
"STORYBOARD_NAME_PREFIX[sdk=appletvsimulator*]" = TV;
"STORYBOARD_NAME_PREFIX[sdk=iphoneos*]" = UI;
"STORYBOARD_NAME_PREFIX[sdk=iphonesimulator*]" = UI;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.2;
};
name = Debug;
};
@@ -375,6 +418,8 @@
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipTests;
PRODUCT_NAME = "$(TARGET_NAME)";
STORYBOARD_NAME_PREFIX = "";
SWIFT_VERSION = 4.2;
};
name = Release;
};
@@ -386,20 +431,28 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 5.1;
CURRENT_PROJECT_VERSION = 7.0.0;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -424,7 +477,7 @@
ONLY_ACTIVE_ARCH = YES;
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0.2;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
VERSIONING_SYSTEM = "apple-generic";
@@ -441,20 +494,28 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 5.1;
CURRENT_PROJECT_VERSION = 7.0.0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -472,7 +533,7 @@
MTL_ENABLE_DEBUG_INFO = NO;
SUPPORTED_PLATFORMS = "macosx watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0.2;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
VALIDATE_PRODUCT = YES;
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -40,8 +40,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.0.0</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.0.0</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.
+2 -16
View File
@@ -19,7 +19,7 @@ It's aimed to be as simple as possible yet provide rich functionality usual for
* You start by creating `let container = DependencyContainer()` and **registering your dependencies, by associating a _protocol_ or _type_ to a `factory`** using `container.register { MyService() as Service }`.
* Then you can call `container.resolve() as Service` to **resolve an instance of _protocol_ or _type_** using that `DependencyContainer`.
* You can easily use Dip along with **Storyboards and Nibs** - checkout **[Dip-UI](https://github.com/AliSoftware/Dip-UI)** extensions. There is also a **[code generator](https://github.com/ilyapuchka/dipgen)** that can help to simplify registering new components.
* You can easily use Dip along with **Storyboards and Nibs** . There is also a **[code generator](https://github.com/ilyapuchka/dipgen)** that can help to simplify registering new components.
<details>
<summary>Basic usage</summary>
@@ -148,27 +148,13 @@ File an issue if you have any question. Pull requests are warmly welcome too.
## Installation
Since version 5.0.0 Dip is built with Swift 3.0. You can install Dip using your favorite dependency manager:
You can install Dip using your favorite dependency manager:
<details>
<summary>CocoaPods</summary>
`pod "Dip"`
To build for Swift 2.3 add this code to the bottom of your Podfile
```ruby
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '2.3'
end
end
end
```
> You need at least 1.1.0.rc.2 version of CocoaPods.
</details>
<details>
@@ -279,7 +279,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0800;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = AliSoftware;
TargetAttributes = {
0990225E1BC123C000E76F43 = {
@@ -427,13 +427,23 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -461,7 +471,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 4.0;
};
name = Debug;
};
@@ -473,13 +483,23 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -498,7 +518,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 4.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -40,8 +40,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
@@ -1,5 +1,15 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
@@ -31,6 +41,16 @@
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
@@ -62,6 +82,16 @@
"idiom" : "ipad",
"filename" : "Icon-152.png",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
+1 -1
View File
@@ -9,7 +9,7 @@
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<string>7.0.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
@@ -13,7 +13,7 @@ struct DummyStarshipProvider : StarshipProviderAPI {
var pilotName: String
func fetchIDs(completion: @escaping ([Int]) -> Void) {
let nbShips = pilotName.characters.count
let nbShips = pilotName.count
completion(Array(0..<nbShips))
}
@@ -27,8 +27,8 @@ struct SWAPIPersonProvider : PersonProviderAPI {
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
// Extract URLs (flatten to ignore invalid ones)
let urlStrings = results.flatMap({ $0["url"] as? String })
let ids = urlStrings.flatMap(idFromURLString)
let urlStrings = results.compactMap({ $0["url"] as? String })
let ids = urlStrings.compactMap(idFromURLString)
completion(ids)
}
@@ -61,7 +61,7 @@ struct SWAPIPersonProvider : PersonProviderAPI {
hairColor: hairColor,
eyeColor: eyeColor,
gender: Gender(rawValue: gender),
starshipIDs: starshipURLStrings.flatMap(idFromURLString)
starshipIDs: starshipURLStrings.compactMap(idFromURLString)
)
completion(person)
}
@@ -27,8 +27,8 @@ struct SWAPIStarshipProvider : StarshipProviderAPI {
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
// Extract URLs (flatten to ignore invalid ones)
let urlStrings = results.flatMap({ $0["url"] as? String })
let ids = urlStrings.flatMap(idFromURLString)
let urlStrings = results.compactMap({ $0["url"] as? String })
let ids = urlStrings.compactMap(idFromURLString)
completion(ids)
}
@@ -59,7 +59,7 @@ struct SWAPIStarshipProvider : StarshipProviderAPI {
manufacturer: manufacturer,
crew: crew,
passengers: passengers,
pilotIDs: pilotIDStrings.flatMap(idFromURLString)
pilotIDs: pilotIDStrings.compactMap(idFromURLString)
)
completion(ship)
}
+1 -1
View File
@@ -9,7 +9,7 @@
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<string>7.0.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
+2 -2
View File
@@ -256,7 +256,7 @@ public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropert
}
class _InjectedPropertyBox<T> {
public class _InjectedPropertyBox<T> {
let required: Bool
let didInject: (T) -> ()
@@ -275,7 +275,7 @@ class _InjectedPropertyBox<T> {
do {
container.context.key = container.context.key.tagged(with: tag)
let key = DefinitionKey(type: T.self, typeOfArguments: Void.self, tag: tag?.dependencyTag)
return try resolve(with: container, key: key, builder: { factory in try factory() }) as? T
return try resolve(with: container, key: key, builder: { (factory: (Any) throws -> Any) in try factory(()) }) as? T
}
catch {
let error = DipError.autoInjectionFailed(label: container.context.injectedInProperty, type: container.context.resolvingType, underlyingError: error)
+12 -12
View File
@@ -35,10 +35,10 @@ public enum ComponentScope {
```
container.register { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer = container.resolve() as ServiceConsumer
consumer.service1 !== consumer.service2 //true
@@ -59,10 +59,10 @@ public enum ComponentScope {
```
container.register { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer1 = container.resolve() as ServiceConsumer
let consumer2 = container.resolve() as ServiceConsumer
@@ -89,10 +89,10 @@ public enum ComponentScope {
```
container.register(.singleton) { ServiceImp() as Service }
container.register {
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
ServiceConsumerImp(
service1: try container.resolve() as Service
service2: try container.resolve() as Service
) as ServiceConsumer
}
let consumer1 = container.resolve() as ServiceConsumer
let consumer2 = container.resolve() as ServiceConsumer
+11 -11
View File
@@ -23,7 +23,7 @@
//
///A key used to store definitons in a container.
public struct DefinitionKey : Hashable, CustomStringConvertible {
public struct DefinitionKey: Hashable, CustomStringConvertible {
public let type: Any.Type
public let typeOfArguments: Any.Type
public private(set) var tag: DependencyContainer.Tag?
@@ -47,15 +47,15 @@ public struct DefinitionKey : Hashable, CustomStringConvertible {
tagged.tag = tag
return tagged
}
}
/// Check two definition keys on equality by comparing their `type`, `factoryType` and `tag` properties.
public func ==(lhs: DefinitionKey, rhs: DefinitionKey) -> Bool {
return
lhs.type == rhs.type &&
/// Check two definition keys on equality by comparing their `type`, `factoryType` and `tag` properties.
public static func ==(lhs: DefinitionKey, rhs: DefinitionKey) -> Bool {
return
lhs.type == rhs.type &&
lhs.typeOfArguments == rhs.typeOfArguments &&
lhs.tag == rhs.tag
}
}
///Dummy protocol to store definitions for different types in collection
@@ -144,7 +144,7 @@ public final class Definition<T, U>: DefinitionType {
//MARK: - TypeForwardingDefinition
/// Types that can be resolved using this definition.
private(set) var implementingTypes: [Any.Type] = [(T?).self, (T!).self]
private(set) var implementingTypes: [Any.Type] = [(T?).self]
/// Return `true` if type can be resolved using this definition
func doesImplements(type aType: Any.Type) -> Bool {
@@ -198,7 +198,7 @@ public final class Definition<T, U>: DefinitionType {
//MARK: - _Definition
protocol _Definition: DefinitionType, AutoWiringDefinition, TypeForwardingDefinition {
protocol _Definition: AutoWiringDefinition, TypeForwardingDefinition {
var type: Any.Type { get }
var scope: ComponentScope { get }
var weakFactory: ((Any) throws -> Any)! { get }
@@ -208,8 +208,8 @@ protocol _Definition: DefinitionType, AutoWiringDefinition, TypeForwardingDefini
//MARK: - Type Forwarding
protocol _TypeForwardingDefinition: TypeForwardingDefinition, _Definition {
weak var forwardsTo: _TypeForwardingDefinition? { get }
protocol _TypeForwardingDefinition: _Definition {
var forwardsTo: _TypeForwardingDefinition? { get }
var forwardsFrom: [_TypeForwardingDefinition] { get set }
func _implements(type aType: Any.Type)
func _implements(types aTypes: [Any.Type])
+48 -20
View File
@@ -34,7 +34,7 @@ public final class DependencyContainer {
- seealso: `DependencyTagConvertible`
*/
public enum Tag: Equatable {
public enum Tag {
case String(StringLiteralType)
case Int(IntegerLiteralType)
}
@@ -50,7 +50,7 @@ public final class DependencyContainer {
private var _weakCollaborators: [WeakBox<DependencyContainer>] = []
var _collaborators: [DependencyContainer] {
get {
return _weakCollaborators.flatMap({ $0.value })
return _weakCollaborators.compactMap({ $0.value })
}
set {
_weakCollaborators = newValue.filter({ $0 !== self }).map(WeakBox.init)
@@ -167,12 +167,15 @@ extension DependencyContainer {
/// The label of the property where resolved instance will be auto-injected.
private(set) public var injectedInProperty: String?
let inCollaboration: Bool
var logErrors: Bool = true
init(key: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String?) {
init(key: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String?, inCollaboration: Bool) {
self.key = key
self.injectedInType = injectedInType
self.injectedInProperty = injectedInProperty
self.inCollaboration = inCollaboration
}
public var debugDescription: String {
@@ -196,7 +199,7 @@ extension DependencyContainer {
/// Pushes new context created with provided values and calls block. When block returns previous context is restored.
/// When popped to initial (root) context will release all references to resolved instances and call `Resolvable` callbacks.
func inContext<T>(key aKey: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String? = nil, logErrors: Bool! = nil, block: () throws -> T) rethrows -> T {
func inContext<T>(key aKey: DefinitionKey, injectedInType: Any.Type?, injectedInProperty: String? = nil, inCollaboration: Bool = false, container: DependencyContainer? = nil, logErrors: Bool! = nil, block: () throws -> T) rethrows -> T {
let key = aKey
return try threadSafe {
let currentContext = self.context
@@ -207,6 +210,10 @@ extension DependencyContainer {
//clean instances pool if it is owned not by other container
if context == nil {
resolvedInstances.resolvedInstances.removeAll()
for (key, instance) in resolvedInstances.sharedWeakSingletons {
if resolvedInstances.sharedWeakSingletons[key] is WeakBoxType { continue }
resolvedInstances.sharedWeakSingletons[key] = WeakBox(instance)
}
for (key, instance) in resolvedInstances.weakSingletons {
if resolvedInstances.weakSingletons[key] is WeakBoxType { continue }
resolvedInstances.weakSingletons[key] = WeakBox(instance)
@@ -222,7 +229,8 @@ extension DependencyContainer {
context = Context(
key: key,
injectedInType: injectedInType,
injectedInProperty: injectedInProperty
injectedInProperty: injectedInProperty,
inCollaboration: inCollaboration
)
context.logErrors = logErrors ?? currentContext?.logErrors ?? true
@@ -258,17 +266,17 @@ extension DependencyContainer {
_collaborators += containers
for container in containers {
container._collaborators += [self]
container.resolvedInstances.singletonsBox = self.resolvedInstances.singletonsBox
container.resolvedInstances.weakSingletonsBox = self.resolvedInstances.weakSingletonsBox
container.resolvedInstances.sharedSingletonsBox = self.resolvedInstances.sharedSingletonsBox
container.resolvedInstances.sharedWeakSingletonsBox = self.resolvedInstances.sharedWeakSingletonsBox
updateCollaborationReferences(between: container, and: self)
}
}
private func updateCollaborationReferences(between container: DependencyContainer, and collaborator: DependencyContainer) {
for container in container._collaborators {
guard container.resolvedInstances.singletonsBox !== collaborator.resolvedInstances.singletonsBox else { continue }
container.resolvedInstances.singletonsBox = collaborator.resolvedInstances.singletonsBox
container.resolvedInstances.weakSingletonsBox = collaborator.resolvedInstances.weakSingletonsBox
guard container.resolvedInstances.sharedSingletonsBox !== collaborator.resolvedInstances.sharedSingletonsBox else { continue }
container.resolvedInstances.sharedSingletonsBox = collaborator.resolvedInstances.sharedSingletonsBox
container.resolvedInstances.sharedWeakSingletonsBox = collaborator.resolvedInstances.sharedWeakSingletonsBox
updateCollaborationReferences(between: container, and: collaborator)
}
}
@@ -291,11 +299,23 @@ extension DependencyContainer {
let context = collaborator.context
collaborator.context = self.context
defer {
collaborator.resolvedInstances = resolvedInstances
collaborator.context = context
collaborator.resolvedInstances = resolvedInstances
for (key, resolvedSingleton) in self.resolvedInstances.singletons {
collaborator.resolvedInstances.singletons[key] = resolvedSingleton
}
for (key, resolvedSingleton) in self.resolvedInstances.weakSingletons {
guard collaborator.definition(matching: key) == nil else { continue }
collaborator.resolvedInstances.weakSingletons[key] = resolvedSingleton is WeakBoxType ? resolvedSingleton : WeakBox(resolvedSingleton)
}
for (key, resolved) in self.resolvedInstances.resolvedInstances {
guard collaborator.definition(matching: key) == nil else { continue }
collaborator.resolvedInstances.resolvedInstances[key] = resolved
}
}
let resolved = try collaborator.inContext(key:key, injectedInType: self.context.injectedInType, injectedInProperty: self.context.injectedInProperty, logErrors: false) {
let resolved = try collaborator.inContext(key:key, injectedInType: self.context.injectedInType, injectedInProperty: self.context.injectedInProperty, inCollaboration: true, logErrors: false) {
try collaborator._resolve(key: key, builder: builder)
}
@@ -336,6 +356,8 @@ extension DependencyContainer {
definitions[key] = nil
resolvedInstances.singletons[key] = nil
resolvedInstances.weakSingletons[key] = nil
resolvedInstances.sharedSingletons[key] = nil
resolvedInstances.sharedWeakSingletons[key] = nil
}
}
@@ -348,6 +370,8 @@ extension DependencyContainer {
definitions.removeAll()
resolvedInstances.singletons.removeAll()
resolvedInstances.weakSingletons.removeAll()
resolvedInstances.sharedSingletons.removeAll()
resolvedInstances.sharedWeakSingletons.removeAll()
bootstrapped = false
}
}
@@ -477,13 +501,17 @@ extension DependencyContainer.Tag: ExpressibleByIntegerLiteral {
}
public func ==(lhs: DependencyContainer.Tag, rhs: DependencyContainer.Tag) -> Bool {
switch (lhs, rhs) {
case let (.String(lhsString), .String(rhsString)):
return lhsString == rhsString
case let (.Int(lhsInt), .Int(rhsInt)):
return lhsInt == rhsInt
default:
return false
extension DependencyContainer.Tag: Equatable {
public static func ==(lhs: DependencyContainer.Tag, rhs: DependencyContainer.Tag) -> Bool {
switch (lhs, rhs) {
case let (.String(lhsString), .String(rhsString)):
return lhsString == rhsString
case let (.Int(lhsInt), .Int(rhsInt)):
return lhsInt == rhsInt
default:
return false
}
}
}
+2
View File
@@ -71,6 +71,8 @@ extension DependencyContainer {
definitions[key] = definition
resolvedInstances.singletons[key] = nil
resolvedInstances.weakSingletons[key] = nil
resolvedInstances.sharedSingletons[key] = nil
resolvedInstances.sharedWeakSingletons[key] = nil
if .eagerSingleton == definition.scope {
bootstrapQueue.append({ _ = try self.resolve(tag: tag) as T })
+78 -34
View File
@@ -46,7 +46,7 @@ extension DependencyContainer {
- seealso: `register(_:type:tag:factory:)`
*/
public func resolve<T>(tag: DependencyTagConvertible? = nil) throws -> T {
return try resolve(tag: tag) { factory in try factory() }
return try _resolve(tag: tag) { (factory: () throws -> T) in try factory() }
}
/**
@@ -73,7 +73,7 @@ extension DependencyContainer {
- seealso: `resolve(tag:)`, `register(_:type:tag:factory:)`
*/
public func resolve(_ type: Any.Type, tag: DependencyTagConvertible? = nil) throws -> Any {
return try resolve(type, tag: tag) { factory in try factory() }
return try resolve(type, tag: tag) { (factory: () throws -> Any) in try factory() }
}
/**
@@ -103,7 +103,11 @@ extension DependencyContainer {
public func resolve<T, U>(tag: DependencyTagConvertible? = nil, builder: ((U) throws -> T) throws -> T) throws -> T {
return try _resolve(tag: tag, builder: builder)
}
public func resolve<T>(tag: DependencyTagConvertible? = nil, builder: (() throws -> T) throws -> T) throws -> T {
return try _resolve(tag: tag, builder: builder)
}
/**
Resolve an instance of provided type using builder closure. Weakly-typed alternative of `resolve(tag:builder:)`
@@ -113,13 +117,37 @@ extension DependencyContainer {
return try _resolve(type: type, tag: tag, builder: builder)
}
public func resolve(_ type: Any.Type, tag: DependencyTagConvertible? = nil, builder: (() throws -> Any) throws -> Any) throws -> Any {
return try _resolve(type: type, tag: tag, builder: builder)
}
}
extension DependencyContainer {
func _resolve<T>(tag aTag: DependencyTagConvertible? = nil, builder: (() throws -> T) throws -> T) throws -> T {
return try resolve(T.self, tag: aTag, builder: { factory in
try withoutActuallyEscaping(factory, do: { (factory) throws -> T in
try builder({ try factory() as! T })
})
}) as! T
}
func _resolve(type aType: Any.Type, tag: DependencyTagConvertible? = nil, builder: (() throws -> Any) throws -> Any) throws -> Any {
let key = DefinitionKey(type: aType, typeOfArguments: Void.self, tag: tag?.dependencyTag)
return try inContext(key:key, injectedInType: context?.resolvingType) {
try self._resolve(key: key, builder: { definition in
try builder { try definition.weakFactory(()) }
})
}
}
func _resolve<T, U>(tag aTag: DependencyTagConvertible? = nil, builder: ((U) throws -> T) throws -> T) throws -> T {
return try resolve(T.self, tag: aTag, builder: { factory in
try builder({ try factory($0) as! T })
try withoutActuallyEscaping(factory, do: { (factory) throws -> T in
try builder({ try factory($0) as! T })
})
}) as! T
}
@@ -136,7 +164,15 @@ extension DependencyContainer {
/// Lookup definition by the key and use it to resolve instance. Fallback to the key with `nil` tag.
func _resolve<T>(key aKey: DefinitionKey, builder: (_Definition) throws -> T) throws -> T {
guard let matching = self.definition(matching: aKey) else {
return try collaboratingResolve(key: aKey, builder: builder) ?? autowire(key: aKey)
do {
return try autowire(key: aKey)
} catch {
if let resolved = collaboratingResolve(key: aKey, builder: builder) {
return resolved
} else {
throw error
}
}
}
let (key, definition) = matching
@@ -163,7 +199,7 @@ extension DependencyContainer {
That happens because when Optional is casted to Any Swift can not implicitly unwrap it with as operator.
As a workaround we detect boxing here and unwrap it so that we return not a box, but wrapped instance.
*/
if let box = resolvedInstance as? BoxType, let unboxed = box.unboxed as? T {
if let box = resolvedInstance as? BoxType, let unboxedAny = box.unboxed, let unboxed = unboxedAny as? T {
resolvedInstance = unboxed
}
@@ -175,7 +211,7 @@ extension DependencyContainer {
return previouslyResolved
}
resolvedInstances[key: key, inScope: definition.scope] = resolvedInstance
resolvedInstances[key: key, inScope: definition.scope, context: context] = resolvedInstance
if let resolvable = resolvedInstance as? Resolvable {
resolvedInstances.resolvableInstances.append(resolvable)
@@ -191,7 +227,7 @@ extension DependencyContainer {
private func previouslyResolved<T>(for definition: _Definition, key: DefinitionKey) -> T? {
//first check if exact key was already resolved
if let previouslyResolved = resolvedInstances[key: key, inScope: definition.scope] as? T {
if let previouslyResolved: T = resolvedInstances[key: key, inScope: definition.scope, context: context] {
return previouslyResolved
}
//then check if any related type was already resolved
@@ -199,7 +235,7 @@ extension DependencyContainer {
DefinitionKey(type: $0, typeOfArguments: key.typeOfArguments, tag: key.tag)
})
for key in keys {
if let previouslyResolved = resolvedInstances[key: key, inScope: definition.scope] as? T {
if let previouslyResolved: T = resolvedInstances[key: key, inScope: definition.scope, context: context] {
return previouslyResolved
}
}
@@ -207,7 +243,7 @@ extension DependencyContainer {
}
/// Searches for definition that matches provided key
private func definition(matching key: DefinitionKey) -> KeyDefinitionPair? {
func definition(matching key: DefinitionKey) -> KeyDefinitionPair? {
if let definition = (self.definitions[key] ?? self.definitions[key.tagged(with: nil)]) {
return (key, definition)
}
@@ -230,41 +266,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
}
}
}
+18 -17
View File
@@ -65,7 +65,7 @@ extension DependencyContainer {
container.register(Client.self, factory: ClientImp.init(service:))
```
*/
@discardableResult public func register<T>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping () throws -> T) -> Definition<T, ()> {
@discardableResult public func register<T>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (()) throws -> T) -> Definition<T, ()> {
let definition = DefinitionBuilder<T, ()> {
$0.scope = scope
$0.factory = factory
@@ -127,7 +127,7 @@ extension DependencyContainer {
- seealso: `register(_:type:tag:factory:)`
*/
@discardableResult public func register<T, A>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A) throws -> T) -> Definition<T, A> {
@discardableResult public func register<T, A>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A)) throws -> T) -> Definition<T, A> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 1) { container, tag in try factory(container.resolve(tag: tag)) }
}
@@ -167,13 +167,14 @@ extension DependencyContainer {
// MARK: 2 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B) throws -> T) -> Definition<T, (A, B)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 2) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag)) }
@discardableResult public func register<T, A, B>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A, B)
) throws -> T) -> Definition<T, (A, B)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 2) { container, tag in try factory((container.resolve(tag: tag), container.resolve(tag: tag))) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2) }
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2)) } as! T
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
@@ -184,13 +185,13 @@ extension DependencyContainer {
// MARK: 3 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C) throws -> T) -> Definition<T, (A, B, C)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 3) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
@discardableResult public func register<T, A, B, C>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A, B, C)) throws -> T) -> Definition<T, (A, B, C)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 3) { container, tag in try factory((container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag))) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3) }
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3)) } as! T
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
@@ -201,13 +202,13 @@ extension DependencyContainer {
// MARK: 4 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C, D>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C, D) throws -> T) -> Definition<T, (A, B, C, D)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 4) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
@discardableResult public func register<T, A, B, C, D>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A, B, C, D)) throws -> T) -> Definition<T, (A, B, C, D)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 4) { container, tag in try factory((container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag))) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4) }
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4)) } as! T
}
/// - seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
@@ -218,13 +219,13 @@ extension DependencyContainer {
// MARK: 5 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C, D, E>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C, D, E) throws -> T) -> Definition<T, (A, B, C, D, E)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 5) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
@discardableResult public func register<T, A, B, C, D, E>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A, B, C, D, E)) throws -> T) -> Definition<T, (A, B, C, D, E)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 5) { container, tag in try factory((container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag))) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D, E>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4, arg5) }
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5)) } as! T
}
///- seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
@@ -235,13 +236,13 @@ extension DependencyContainer {
// MARK: 6 Runtime Arguments
/// - seealso: `register(_:type:tag:factory:)`
@discardableResult public func register<T, A, B, C, D, E, F>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping (A, B, C, D, E, F) throws -> T) -> Definition<T, (A, B, C, D, E, F)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 6) { container, tag in try factory(container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag)) }
@discardableResult public func register<T, A, B, C, D, E, F>(_ scope: ComponentScope = .shared, type: T.Type = T.self, tag: DependencyTagConvertible? = nil, factory: @escaping ((A, B, C, D, E, F)) throws -> T) -> Definition<T, (A, B, C, D, E, F)> {
return register(scope: scope, type: type, tag: tag, factory: factory, numberOfArguments: 6) { container, tag in try factory((container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag), container.resolve(tag: tag))) }
}
/// - seealso: `resolve(tag:arguments:)`
public func resolve<T, A, B, C, D, E, F>(tag: DependencyTagConvertible? = nil, arguments arg1: A, _ arg2: B, _ arg3: C, _ arg4: D, _ arg5: E, _ arg6: F) throws -> T {
return try resolve(tag: tag) { factory in try factory(arg1, arg2, arg3, arg4, arg5, arg6) }
return try resolve(T.self, tag: tag) { factory in try factory((arg1, arg2, arg3, arg4, arg5, arg6)) } as! T
}
/// - seealso: `resolve(_:tag:)`, `resolve(tag:arguments:)`
+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)) && !SWIFT_PACKAGE
extension DependencyContainer {
///Containers that will be used to resolve dependencies of instances, created by stroyboards.
static public var uiContainers: [DependencyContainer] = {
#if os(watchOS)
swizzleAwakeWithContext
#endif
return []
}()
/**
Resolves dependencies of passed in instance.
Use this method to resolve dependencies of object created by storyboard.
The type of the instance should be registered in the container.
You should call this method only from implementation of `didInstantiateFromStoryboard(_:tag:)`
of `StoryboardInstantiatable` protocol if you override its default implementation.
This method will do the same as `resolve(tag:) as T`, but instead of creating
a new intance with a registered factory it will use passed in instance as a resolved instance.
- parameters:
- instance: The object which dependencies should be resolved
- tag: An optional tag used to register the type (`T`) in the container
**Example**:
```swift
class ViewController: UIViewController, ServiceDelegate, StoryboardInstantiatable {
var service: Service?
func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag?) throws {
try container.resolveDependencies(of: self as ServiceDelegate, tag: "vc")
}
}
class ServiceImp: Service {
weak var delegate: ServiceDelegate?
}
container.register(tag: "vc") { ViewController() }
.resolvingProperties { container, controller in
controller.service = try container.resolve() as Service
controller.service.delegate = controller
}
container.register { ServiceImp() as Service }
```
- seealso: `register(_:type:tag:factory:)`, `didInstantiateFromStoryboard(_:tag:)`
*/
public func resolveDependencies<T>(of instance: T, tag: Tag? = nil) throws {
_ = try resolve(tag: tag) { (_: () throws -> T) in instance }
}
/**
Register storyboard type `T` which has to conform to `StoryboardInstantiatable` and associate it with an optional tag.
- parameters:
- type: Storyboard type to register definition for.
- tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
- returns: A registered definition.
- note: This method will register concrete types. If you need to register
as abstract types you should use standard `register` method from Dip.
You should cast the factory return type to the protocol you want to
register it for (unless you want to register concrete type) or
provide `type` parameter.
- seealso: `Definition`, `ComponentScope`, `DependencyTagConvertible`
**Example**:
```swift
// Register MyViewController
container.register(storyboardType: MyViewController.self)
// or
container.register(tag: "myVC") { MyViewController() as MyViewControllerType }
```
*/
public func register<T: NSObject>(storyboardType type: T.Type, tag: DependencyTagConvertible? = nil) -> Dip.Definition<T, ()> where T: StoryboardInstantiatable {
return register(.unique, type: type, tag: tag, factory: { T() })
}
}
#if os(watchOS)
public protocol StoryboardInstantiatableType {}
#else
public typealias StoryboardInstantiatableType = NSObjectProtocol
#endif
public protocol StoryboardInstantiatable: StoryboardInstantiatableType {
/**
This method will be called if you set a `dipTag` attirbute on the object in a storyboard
that conforms to `StoryboardInstantiatable` protocol.
- parameters:
- tag: The tag value, that was set on the object in a storyboard
- container: The `DependencyContainer` associated with storyboards
The type that implements `StoryboardInstantiatable` protocol should be registered in `UIStoryboard.container`.
Default implementation of that method calls `resolveDependenciesOf(_:tag:)`
and pass it `self` instance and the tag.
Usually you will not need to override the default implementation of this method
if you registered the type of the instance as a concrete type in the container.
Then you only need to add conformance to `StoryboardInstantiatable`.
You may want to override it if you want to add custom logic before/after resolving dependencies
or you want to resolve the instance as implementation of some protocol which it conforms to.
- warning: This method will be called after `init?(coder:)` but before `awakeFromNib` method of `NSObject`.
On watchOS this method will be called before `awakeWithContext(_:)`.
**Example**:
```swift
extension MyViewController: SomeProtocol { ... }
extension MyViewController: StoryboardInstantiatable {
func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag) throws {
//resolve dependencies of the instance as SomeProtocol type
try container.resolveDependencies(of: self as SomeProtocol, tag: tag)
//do some additional setup here
}
}
```
*/
func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag?) throws
}
extension StoryboardInstantiatable {
public func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag?) throws {
try container.resolveDependencies(of: self, tag: tag)
}
}
#if os(iOS) || os(tvOS) || os(OSX)
#if os(iOS) || os(tvOS)
import UIKit
#elseif os(OSX)
import AppKit
#endif
let DipTagAssociatedObjectKey = UnsafeMutablePointer<Int8>.allocate(capacity: 1)
extension NSObject {
///A string tag that will be used to resolve dependencies of this instance
///if it implements `StoryboardInstantiatable` protocol.
@objc private(set) public var dipTag: String? {
get {
return objc_getAssociatedObject(self, DipTagAssociatedObjectKey) as? String
}
set {
objc_setAssociatedObject(self, DipTagAssociatedObjectKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
guard let instantiatable = self as? StoryboardInstantiatable else { return }
let tag = dipTag.map(DependencyContainer.Tag.String)
for (index, container) in DependencyContainer.uiContainers.enumerated() {
do {
log("Trying to resolve \(type(of: self)) with UI container at index \(index)")
try instantiatable.didInstantiateFromStoryboard(container, tag: tag)
log("Resolved \(type(of: self))")
return
} catch { }
}
}
}
}
func log(_ message: Any) {
if Dip.LogLevel.Errors.rawValue <= Dip.logLevel.rawValue {
Dip.logger(logLevel, message)
}
}
#else
import WatchKit
let swizzleAwakeWithContext: Void = {
let originalSelector = #selector(WKInterfaceController.awake(withContext:))
let swizzledSelector = #selector(WKInterfaceController.dip_awake(withContext:))
guard let originalMethod = class_getInstanceMethod(WKInterfaceController.self, originalSelector),
let swizzledMethod = class_getInstanceMethod(WKInterfaceController.self, swizzledSelector) else { return }
let didAddMethod = class_addMethod(WKInterfaceController.self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(WKInterfaceController.self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}()
extension WKInterfaceController: StoryboardInstantiatableType {
@objc func dip_awake(withContext context: AnyObject?) {
defer { self.dip_awake(withContext: context) }
guard let instantiatable = self as? StoryboardInstantiatable else { return }
for container in DependencyContainer.uiContainers {
guard let _ = try? instantiatable.didInstantiateFromStoryboard(container, tag: nil) else { continue }
break
}
}
}
#endif
#endif
-6
View File
@@ -81,12 +81,6 @@ extension Definition {
return implements(a).implements(b).implements(c)
}
///Registers definition for types passed as parameters
@available(*, deprecated: 5.1.0)
@discardableResult public func implements<A, B, C, D>(_ a: A.Type, _ b: B.Type, c: C.Type, d: D.Type) -> Definition {
return implements(a).implements(b).implements(c).implements(d)
}
///Registers definition for types passed as parameters
@discardableResult public func implements<A, B, C, D>(_ a: A.Type, _ b: B.Type, _ c: C.Type, _ d: D.Type) -> Definition {
return implements(a).implements(b).implements(c).implements(d)
-5
View File
@@ -48,11 +48,6 @@ extension Optional: BoxType {
}
}
extension ImplicitlyUnwrappedOptional: BoxType {
var unboxed: Any? {
return self ?? nil
}
}
class Box<T> {
var unboxed: T
+2 -2
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}
}
@@ -47,7 +47,7 @@ private class ServerImp: Server {
weak var anotherClient: Client!
weak var _optionalProperty = InjectedWeak<AnyObject>(required: false)
var _optionalProperty = InjectedWeak<AnyObject>(required: false)
}
private class ClientImp: Client {
+4 -12
View File
@@ -112,7 +112,7 @@ class AutoWiringTests: XCTestCase {
//2 args
var factoryWithMostNumberOfArgumentsCalled = false
container.register { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }
.resolvingProperties { _ in
.resolvingProperties { _,_ in
factoryWithMostNumberOfArgumentsCalled = true
}
@@ -164,7 +164,7 @@ class AutoWiringTests: XCTestCase {
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }
//2 arg tagged
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }.resolvingProperties { _ in
container.register(tag: "tag") { AutoWiredClientImp(service1: $0, service2: $1) as AutoWiredClient }.resolvingProperties { _,_ in
taggedFactoryWithMostNumberOfArgumentsCalled = true
}
@@ -189,7 +189,7 @@ class AutoWiringTests: XCTestCase {
//1 arg tagged
var taggedFactoryCalled = false
container.register(tag: "tag") { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }.resolvingProperties { _ in
container.register(tag: "tag") { AutoWiredClientImp(service1: try self.container.resolve(), service2: $0) as AutoWiredClient }.resolvingProperties { _,_ in
taggedFactoryCalled = true
}
@@ -208,7 +208,7 @@ class AutoWiringTests: XCTestCase {
//1 arg
var notTaggedFactoryWithMostNumberOfArgumentsCalled = false
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }.resolvingProperties { _ in
container.register { AutoWiredClientImp(service1: $0, service2: try self.container.resolve()) as AutoWiredClient }.resolvingProperties { _,_ in
notTaggedFactoryWithMostNumberOfArgumentsCalled = true
}
@@ -467,17 +467,9 @@ class AutoWiringTests: XCTestCase {
AssertNoThrow(expression: resolved = try container.resolve() as AutoWiredClient?)
XCTAssertNotNil(resolved)
//when
AssertNoThrow(expression: resolved = try container.resolve() as AutoWiredClient!)
XCTAssertNotNil(resolved)
//when
AssertNoThrow(expression: resolved = try container.resolve(tag: "tag") as AutoWiredClient?)
XCTAssertNotNil(resolved)
//when
AssertNoThrow(expression: resolved = try container.resolve(tag: "tag") as AutoWiredClient!)
XCTAssertNotNil(resolved)
}
}
+1 -7
View File
@@ -301,23 +301,17 @@ class ComponentScopeTests: XCTestCase {
func testThatItReusesResolvedInstanceWhenResolvingOptional() {
var otherService: Service!
var impOtherService: Service!
var anyOtherService: Any!
var anyImpOtherService: Any!
container.register { ServiceImp1() as Service }
.resolvingProperties { container, service in
otherService = try! container.resolve() as Service?
impOtherService = try! container.resolve() as Service!
anyOtherService = try! container.resolve((Service?).self)
anyImpOtherService = try! container.resolve((Service!).self)
}
let service = try! container.resolve() as Service
XCTAssertTrue(otherService as! ServiceImp1 === service as! ServiceImp1)
XCTAssertTrue(impOtherService as! ServiceImp1 === service as! ServiceImp1)
XCTAssertTrue(anyOtherService as! ServiceImp1 === service as! ServiceImp1)
XCTAssertTrue(anyImpOtherService as! ServiceImp1 === service as! ServiceImp1)
}
func testThatItHoldsWeakReferenceToWeakSingletonInstance() {
+15 -15
View File
@@ -63,7 +63,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
}
@@ -71,7 +71,7 @@ class ContextTests: XCTestCase {
container.register { () -> ServiceImp1 in
XCTAssertTrue(self.container.context.resolvingType == ServiceImp1.self)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertTrue(self.container.context.resolvingType == ServiceImp1.self)
}
@@ -83,7 +83,7 @@ class ContextTests: XCTestCase {
XCTAssertNil(self.container.context.injectedInType)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNil(self.container.context.injectedInType)
let _ = try self.container.resolve() as ServiceImp1
}
@@ -91,7 +91,7 @@ class ContextTests: XCTestCase {
container.register { () -> ServiceImp1 in
XCTAssertTrue(self.container.context.injectedInType == Service.self)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertTrue(self.container.context.injectedInType == Service.self)
}
@@ -104,7 +104,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve(tag: "otherTag") as ServiceImp1
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve(tag: "otherTag") as ServiceImp1
@@ -114,7 +114,7 @@ class ContextTests: XCTestCase {
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("otherTag") ~= self.container.context.tag!)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("otherTag") ~= self.container.context.tag!)
}
@@ -135,7 +135,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(DependencyContainer.Tag.String("injectedTag") ~= self.container.context.tag!)
}
return ServiceImp2()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
if self.container.context.injectedInProperty == "injectedNilTag" {
XCTAssertNil(self.container.context.tag)
}
@@ -149,7 +149,7 @@ class ContextTests: XCTestCase {
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
return ServiceImp2()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
}
@@ -160,14 +160,14 @@ class ContextTests: XCTestCase {
func testThatContextStoresTheTagPassedToResolveWhenAutoWiring() {
container.register { (_: ServiceImp1) -> Service in
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
}
container.register { () -> ServiceImp1 in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
}
@@ -181,7 +181,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.tag)
XCTAssertTrue(DependencyContainer.Tag.String("tag") ~= self.container.context.tag!)
let _ = try self.container.resolve() as ServiceImp1
@@ -190,7 +190,7 @@ class ContextTests: XCTestCase {
container.register { () -> ServiceImp1 in
XCTAssertNil(self.container.context.tag)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNil(self.container.context.tag)
}
@@ -207,7 +207,7 @@ class ContextTests: XCTestCase {
XCTAssertNotNil(self.container.context.injectedInProperty)
XCTAssertTrue(names.contains(self.container.context.injectedInProperty!))
return ServiceImp2()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertNotNil(self.container.context.injectedInProperty)
XCTAssertTrue(names.contains(self.container.context.injectedInProperty!))
}
@@ -239,7 +239,7 @@ class ContextTests: XCTestCase {
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
return ServiceImp1() as Service
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertTrue(self.container.context.resolvingType == Service.self)
let _ = try self.container.resolve() as ServiceImp1
}
@@ -247,7 +247,7 @@ class ContextTests: XCTestCase {
collaborator.register { () -> ServiceImp1 in
XCTAssertTrue(collaborator.context.resolvingType == ServiceImp1.self)
return ServiceImp1()
}.resolvingProperties { _ in
}.resolvingProperties { _,_ in
XCTAssertTrue(collaborator.context.resolvingType == ServiceImp1.self)
}
-1
View File
@@ -116,7 +116,6 @@ class DefinitionTests: XCTestCase {
let def = Definition<Service, ()>(scope: .unique) { ServiceImp() as Service }
XCTAssertTrue(def.implementingTypes.contains(where: { $0 == Service?.self }))
XCTAssertTrue(def.implementingTypes.contains(where: { $0 == Service!.self }))
}
}
+123 -34
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 }
@@ -70,6 +70,7 @@ class DipTests: XCTestCase {
("testThatCollaboratingWithSelfIsIgnored", testThatCollaboratingWithSelfIsIgnored),
("testThatCollaboratingContainersAreWeakReferences", testThatCollaboratingContainersAreWeakReferences),
("testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer", testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer),
("testThatItCanHandleSeparateContainersAndTheirCollaboration", testThatItCanHandleSeparateContainersAndTheirCollaboration)
]
}()
@@ -123,12 +124,6 @@ class DipTests: XCTestCase {
//then
XCTAssertTrue(optService is ServiceImp1)
//and when
let impService = try! container.resolve((Service!).self)
//then
XCTAssertTrue(impService is ServiceImp1)
}
func testThatItResolvesInstanceRegisteredWithTag() {
@@ -152,12 +147,6 @@ class DipTests: XCTestCase {
//then
XCTAssertTrue(optService is ServiceImp1)
//and when
let impService = try! container.resolve((Service!).self, tag: "service")
//then
XCTAssertTrue(impService is ServiceImp1)
}
func testThatItResolvesDifferentInstancesRegisteredForDifferentTags() {
@@ -188,14 +177,6 @@ class DipTests: XCTestCase {
//then
XCTAssertTrue(optService1 is ServiceImp1)
XCTAssertTrue(optService2 is ServiceImp2)
//and when
let impService1 = try! container.resolve((Service!).self, tag: "service1")
let impService2 = try! container.resolve((Service!).self, tag: "service2")
//then
XCTAssertTrue(impService1 is ServiceImp1)
XCTAssertTrue(impService2 is ServiceImp2)
}
func testThatNewRegistrationOverridesPreviousRegistration() {
@@ -241,12 +222,6 @@ class DipTests: XCTestCase {
XCTAssertTrue(resolveDependenciesCalled)
resolveDependenciesCalled = false
//and when
let _ = try! container.resolve((Service!).self)
//then
XCTAssertTrue(resolveDependenciesCalled)
}
func testThatItThrowsErrorIfCanNotFindDefinitionForType() {
@@ -573,12 +548,12 @@ class DipTests: XCTestCase {
}.implements(Service.self)
container.register(tag: "tag") { ServiceImp2() as Service }
.resolvingProperties { _ in
.resolvingProperties { _,_ in
createdService2 = true
}
container.register { (arg: String) in ServiceImp1() }
.resolvingProperties { _ in
.resolvingProperties { _,_ in
createdService3 = true
}
@@ -743,16 +718,16 @@ extension DipTests {
let collaborator4 = DependencyContainer()
collaborator1.collaborate(with: container)
XCTAssertTrue(collaborator1.resolvedInstances.singletonsBox === container.resolvedInstances.singletonsBox)
XCTAssertTrue(collaborator1.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
collaborator2.collaborate(with: container)
XCTAssertTrue(collaborator2.resolvedInstances.singletonsBox === container.resolvedInstances.singletonsBox)
XCTAssertTrue(collaborator2.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
collaborator3.collaborate(with: collaborator1)
XCTAssertTrue(collaborator3.resolvedInstances.singletonsBox === container.resolvedInstances.singletonsBox)
XCTAssertTrue(collaborator3.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
collaborator4.collaborate(with: collaborator2)
XCTAssertTrue(collaborator4.resolvedInstances.singletonsBox === container.resolvedInstances.singletonsBox)
XCTAssertTrue(collaborator4.resolvedInstances.sharedSingletonsBox === container.resolvedInstances.sharedSingletonsBox)
let service1 = try! collaborator1.resolve() as Service
let service2 = try! collaborator2.resolve() as Service
@@ -760,10 +735,124 @@ extension DipTests {
let service4 = try! collaborator4.resolve() as Service
let serviceRoot = try! container.resolve() as Service
XCTAssertTrue(service1 === service2)
XCTAssertTrue(service1 === service3)
XCTAssertTrue(service1 === service4)
XCTAssertTrue(service1 === serviceRoot)
XCTAssertTrue(service2 === serviceRoot)
XCTAssertTrue(service3 === serviceRoot)
XCTAssertTrue(service4 === serviceRoot)
}
class RootService {}
class ServiceClient {
let name: String
let service: RootService
init(name: String, service: RootService) {
self.name = name
self.service = service
}
}
func testThatContainersShareTheirSingletonsOnlyWithCollaborators() {
let container = DependencyContainer()
container.register(.singleton) { RootService() }
let collaborator1 = DependencyContainer()
collaborator1.register(.singleton) {
ServiceClient(name: "1", service: $0)
}
let collaborator2 = DependencyContainer()
collaborator2.register(.singleton) {
ServiceClient(name: "2", service: $0)
}
collaborator1.collaborate(with: container)
collaborator2.collaborate(with: container)
let client2 = try! collaborator2.resolve() as ServiceClient
let client1 = try! collaborator1.resolve() as ServiceClient
XCTAssertEqual(client1.name, "1")
XCTAssertEqual(client2.name, "2")
XCTAssertTrue(client1.service === client2.service)
}
func testThatContainerAutowireBeforeCollaboration() {
let container = DependencyContainer()
container.register(.singleton) { RootService() }
let collaborator1 = DependencyContainer()
collaborator1.register(.singleton) {
ServiceClient(name: "1", service: $0)
}
let collaborator2 = DependencyContainer()
collaborator2.register(.singleton) {
ServiceClient(name: "2", service: $0)
}
collaborator1.collaborate(with: container, collaborator2)
collaborator2.collaborate(with: container, collaborator1)
let client2 = try! collaborator2.resolve() as ServiceClient
let client1 = try! collaborator1.resolve() as ServiceClient
XCTAssertEqual(client1.name, "1")
XCTAssertEqual(client2.name, "2")
XCTAssertTrue(client1.service === client2.service)
}
}
class Manager {}
class AnotherManager {}
class Object {
let manager: Manager?
init(with container: DependencyContainer) {
self.manager = try? container.resolve()
}
}
class Owner {
var manager: Manager?
}
extension DipTests {
func testThatItCanHandleSeparateContainersAndTheirCollaboration() {
let container = self.container
let anotherContainer = DependencyContainer()
anotherContainer.register { Object(with: anotherContainer) }
container.collaborate(with: anotherContainer)
container
.register { Owner() }
.resolvingProperties { $1.manager = try $0.resolve() }
container.register(.singleton) { AnotherManager() }
container.register(.singleton) { Manager() }
let manager: Manager? = try? container.resolve()
let another: AnotherManager? = try? container.resolve()
var owner: Owner? = try? container.resolve(arguments: 1, "")
let object: Object? = try? container.resolve()
owner = try? container.resolve()
let nonNilValues: [Any?] = [another, manager, owner, object, object?.manager]
nonNilValues.forEach { XCTAssertNotNil($0) }
XCTAssertTrue(
owner?.manager
.flatMap { value in
manager.flatMap { $0 === value }
}
?? false
)
}
}
+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
+53 -4
View File
@@ -30,6 +30,25 @@ private protocol ForwardedType: class { }
private class ServiceImp1: NSObject, Service, ForwardedType { }
private class ServiceImp2: NSObject, Service, ForwardedType { }
private protocol Dependency {}
private struct DependencyImpl: Dependency {}
private class DependencyRefImpl: Dependency {}
private struct DependencyClient {
let dep: Dependency
init(dependency: Dependency) {
self.dep = dependency
}
}
private struct OptionalDependencyClient {
let dep: Dependency?
init(dependency: Dependency?) {
self.dep = dependency
}
}
class TypeForwardingTests: XCTestCase {
let container = DependencyContainer()
@@ -44,6 +63,7 @@ class TypeForwardingTests: XCTestCase {
("testThatItCallsResolvedDependenciesBlockProvidedAfterRegistrationWhenResolvingByTypeForwarding",testThatItCallsResolvedDependenciesBlockProvidedAfterRegistrationWhenResolvingByTypeForwarding),
("testThatItFallbackToDefinitionWithNoTagWhenResolvingInstanceByTypeForwarding", testThatItFallbackToDefinitionWithNoTagWhenResolvingInstanceByTypeForwarding),
("testThatItCanResolveOptional", testThatItCanResolveOptional),
("testThatItReusesInstancesResolvedForOptionalType", testThatItReusesInstancesResolvedForOptionalType),
("testThatItFirstUsesTaggedDefinitionWhenResolvingOptional", testThatItFirstUsesTaggedDefinitionWhenResolvingOptional),
("testThatItThrowsErrorWhenResolvingNotImplementedTypeWithTypeForwarding", testThatItThrowsErrorWhenResolvingNotImplementedTypeWithTypeForwarding),
("testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType", testThatItOverridesIfSeveralDefinitionsWithTheSameTagForwardTheSameType),
@@ -154,9 +174,9 @@ class TypeForwardingTests: XCTestCase {
var originalResolvingPropertiesCalled = false
var resolvingPropertiesCalled = false
container.register { ServiceImp1() }
.resolvingProperties { _ in
.resolvingProperties { _,_ in
originalResolvingPropertiesCalled = true
}.implements(Service.self) { _ in
}.implements(Service.self) { _,_ in
resolvingPropertiesCalled = true
}
@@ -184,11 +204,11 @@ class TypeForwardingTests: XCTestCase {
var resolvingPropertiesCalled = false
container.reset()
let definition = container.register { ServiceImp1() }
.implements(Service.self) { container, object in
.implements(Service.self) { _,_ in
resolvingPropertiesCalled = true
}
definition.resolvingProperties { _ in
definition.resolvingProperties { _,_ in
originalResolvingPropertiesCalled = true
}
@@ -252,6 +272,35 @@ class TypeForwardingTests: XCTestCase {
XCTAssertTrue(object is ServiceImp1)
XCTAssertTrue(anyObject is ServiceImp1)
}
func testThatItReusesInstancesResolvedForOptionalType() {
var alreadyResolved = false
container.register(.singleton) { () -> Dependency in
XCTAssertFalse(alreadyResolved)
return DependencyImpl() as Dependency
}
container.register() { DependencyClient(dependency: try! self.container.resolve()) }
container.register() { OptionalDependencyClient(dependency: try! self.container.resolve()) }
let _ = try! container.resolve() as OptionalDependencyClient
let _ = try! container.resolve() as DependencyClient
alreadyResolved = false
let _ = try! container.resolve() as DependencyClient
let _ = try! container.resolve() as OptionalDependencyClient
container.register(.singleton) { () -> Dependency in
XCTAssertFalse(alreadyResolved)
return DependencyRefImpl() as Dependency
}
let client1 = try! container.resolve() as DependencyClient
let client2 = try! container.resolve() as OptionalDependencyClient
XCTAssertTrue(client1.dep as! DependencyRefImpl === client2.dep as! DependencyRefImpl)
}
func testThatItFirstUsesTaggedDefinitionWhenResolvingOptional() {
let expectedTag: DependencyContainer.Tag = .String("tag")