Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ec008a5c0 | |||
| 772bc13daa | |||
| fa4325399a | |||
| f7fbbda748 | |||
| 56b0768d60 | |||
| 8cf87efb95 | |||
| 3aa9b334f1 | |||
| b2a0cda242 | |||
| 82e3d02497 | |||
| 3b2f5a272f | |||
| eab2d424e7 | |||
| 0f2cda0a52 | |||
| 05c02c9645 | |||
| fa086dad8f | |||
| cdc09f5a03 | |||
| b94ed3bea2 | |||
| 0fd70e65dd | |||
| 97e7f4782f | |||
| be0c39ab6b | |||
| 0de45e7d53 | |||
| 3b421d0cff | |||
| f1234bf2b9 | |||
| b0d7153bfe | |||
| b9bf9c4d75 |
@@ -36,3 +36,4 @@ Carthage
|
||||
# SPM
|
||||
.build/
|
||||
Packages
|
||||
.swiftpm
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
5.0.1
|
||||
+26
-1
@@ -12,7 +12,32 @@ matrix:
|
||||
osx_image: xcode10.2
|
||||
language: objective-c
|
||||
before_install:
|
||||
- gem install cocoapods --version 1.4.0 --no-document
|
||||
- gem install cocoapods --version 1.8.4 --no-document
|
||||
- script:
|
||||
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
|
||||
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk macosx -destination 'platform=macOS,arch=x86_64' ONLY_ACTIVE_ARCH=NO | xcpretty -c
|
||||
# - pod spec lint --allow-warnings
|
||||
- carthage build --no-skip-current
|
||||
- swift package clean && swift build && swift test
|
||||
os: osx
|
||||
osx_image: xcode11.2
|
||||
language: objective-c
|
||||
before_install:
|
||||
- gem install cocoapods --version 1.8.4 --no-document
|
||||
- script:
|
||||
- swift package clean && swift build && swift test
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
language: generic
|
||||
before_install:
|
||||
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
|
||||
- cd ..
|
||||
- export SWIFT_VERSION=swift-5.1-RELEASE
|
||||
- wget https://swift.org/builds/swift-5.1-release/ubuntu1404/$SWIFT_VERSION/$SWIFT_VERSION-ubuntu14.04.tar.gz
|
||||
- tar xzf $SWIFT_VERSION-ubuntu14.04.tar.gz
|
||||
- export PATH="${PWD}/${SWIFT_VERSION}-ubuntu14.04/usr/bin:${PATH}"
|
||||
- cd Dip
|
||||
- script:
|
||||
- swift package clean && swift build && swift test
|
||||
os: linux
|
||||
|
||||
+11
-1
@@ -2,7 +2,17 @@
|
||||
|
||||
## Develop
|
||||
|
||||
* You can now use a shorthand syntax for resolving a single property using a key path, i.e. `resolvingProperty(\.value)`. This allows to inject properties without making them publicly writable (they still should be writable, but `private(set)` is good enough) and without manually casting resolved instance to its concrete type to set the property (this will be still done under the hood).
|
||||
## 7.1.1
|
||||
|
||||
* Fixed using `StoryboardInstantiatable` with SPM ([#233](https://github.com/AliSoftware/Dip/pull/233)).
|
||||
|
||||
## 7.1.0
|
||||
|
||||
* You can now use a shorthand syntax for resolving a single property using a key path, i.e. `resolvingProperty(\.value)`.
|
||||
* Swift 5.0 support ([#224](https://github.com/AliSoftware/Dip/pull/224)).
|
||||
* Fixed resolving nested types with the same local names ([#221](https://github.com/AliSoftware/Dip/pull/221)).
|
||||
* `@Injected` and `@IntectedWeak` property wrappers ([#225](https://github.com/AliSoftware/Dip/pull/225)).
|
||||
* Thread safety can be disabled on container level.
|
||||
|
||||
## 7.0.1
|
||||
|
||||
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "Dip"
|
||||
s.version = "7.0.1"
|
||||
s.version = "7.1.1"
|
||||
s.summary = "Dependency Injection for Swift made easy."
|
||||
|
||||
s.description = <<-DESC
|
||||
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
|
||||
|
||||
s.homepage = "https://github.com/AliSoftware/Dip"
|
||||
s.license = 'MIT'
|
||||
s.authors = { "Olivier Halligon" => "olivier@halligon.net", "Ilya Puchka" => "ilya@puchka.me" }
|
||||
s.authors = { "Olivier Halligon" => "olivier@halligon.net", "Ilya Puchka" => "ilyapuchka@gmail.com" }
|
||||
s.source = { :git => "https://github.com/AliSoftware/Dip.git", :tag => s.version.to_s }
|
||||
s.social_media_url = 'https://twitter.com/aligatr'
|
||||
|
||||
@@ -23,4 +23,6 @@ Pod::Spec.new do |s|
|
||||
s.requires_arc = true
|
||||
|
||||
s.source_files = 'Sources/**/*.swift'
|
||||
|
||||
s.swift_version = "5.0", "5.1"
|
||||
end
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>7.0.1</string>
|
||||
<string>7.1.1</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>7.0.1</string>
|
||||
<string>7.1.1</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -13,7 +13,7 @@ On the previous page you saw how auto-wiring helps us to get rid of boilerplate
|
||||
Let's say you have following related components:
|
||||
*/
|
||||
|
||||
protocol Service: class {
|
||||
protocol Service: AnyObject {
|
||||
var logger: Logger? { get }
|
||||
var tracker: Tracker? { get }
|
||||
}
|
||||
@@ -101,11 +101,11 @@ serverWithNoClient.optionalClient.value
|
||||
Another example of using auto-injection is circular dependencies. Let's say you have a `Server` and a `ServerClient` both referencing each other.
|
||||
*/
|
||||
|
||||
protocol Server: class {
|
||||
protocol Server: AnyObject {
|
||||
weak var client: ServerClient? { get }
|
||||
}
|
||||
|
||||
protocol ServerClient: class {
|
||||
protocol ServerClient: AnyObject {
|
||||
var server: Server? { get }
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -13,11 +13,11 @@ Very often we encounter situations when we have circular dependencies between co
|
||||
Let's say you have some network client and it's delegate defined like this:
|
||||
*/
|
||||
|
||||
protocol NetworkClientDelegate: class {
|
||||
protocol NetworkClientDelegate: AnyObject {
|
||||
var networkClient: NetworkClient { get }
|
||||
}
|
||||
|
||||
protocol NetworkClient: class {
|
||||
protocol NetworkClient: AnyObject {
|
||||
weak var delegate: NetworkClientDelegate? { get set }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
public protocol Service: class {}
|
||||
public protocol Service: AnyObject {}
|
||||
|
||||
public class ServiceImp1: Service {
|
||||
public init() {}
|
||||
@@ -22,7 +22,7 @@ public class ServiceImp4: Service {
|
||||
|
||||
}
|
||||
|
||||
public protocol Client: class {
|
||||
public protocol Client: AnyObject {
|
||||
var service: Service {get}
|
||||
init(service: Service)
|
||||
}
|
||||
@@ -74,9 +74,9 @@ public class DataProviderImp: DataProvider {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public protocol ListInteractorOutput: class {}
|
||||
public protocol ListModuleInterface: class {}
|
||||
public protocol ListInteractorInput: class {}
|
||||
public protocol ListInteractorOutput: AnyObject {}
|
||||
public protocol ListModuleInterface: AnyObject {}
|
||||
public protocol ListInteractorInput: AnyObject {}
|
||||
public class ListPresenter: NSObject {
|
||||
public var listInteractor : ListInteractorInput?
|
||||
public var listWireframe : ListWireframe?
|
||||
@@ -96,8 +96,8 @@ public class ListWireframe : NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
public protocol AddModuleDelegate: class {}
|
||||
public protocol AddModuleInterface: class {}
|
||||
public protocol AddModuleDelegate: AnyObject {}
|
||||
public protocol AddModuleInterface: AnyObject {}
|
||||
public class AddWireframe: NSObject {
|
||||
let addPresenter : AddPresenter
|
||||
public init(addPresenter: AddPresenter) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>7.0.1</string>
|
||||
<string>7.1.1</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
///Provides Person entitis fetching them with web service
|
||||
///Provides Person entities fetching them with web service
|
||||
struct SWAPIPersonProvider : PersonProviderAPI {
|
||||
let ws: NetworkLayer
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
protocol FetchableTrait: class {
|
||||
protocol FetchableTrait: AnyObject {
|
||||
associatedtype ObjectType
|
||||
var objects: [ObjectType]? { get set }
|
||||
var batchRequestID: Int { get set }
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>7.0.1</string>
|
||||
<string>7.1.1</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
+204
-78
@@ -78,7 +78,7 @@ extension DependencyContainer {
|
||||
```
|
||||
|
||||
*/
|
||||
public protocol AutoInjectedPropertyBox: class {
|
||||
public protocol AutoInjectedPropertyBox {
|
||||
///The type of wrapped property.
|
||||
static var wrappedType: Any.Type { get }
|
||||
|
||||
@@ -93,40 +93,108 @@ public protocol AutoInjectedPropertyBox: class {
|
||||
func resolve(_ container: DependencyContainer) throws
|
||||
}
|
||||
|
||||
#if swift(>=5.1)
|
||||
/**
|
||||
Use this wrapper to identify _strong_ properties of the instance that should be
|
||||
auto-injected by `DependencyContainer`. Type T can be any type.
|
||||
|
||||
- warning: Do not define this property as optional or container will not be able to inject it.
|
||||
Instead define it with initial value of `Injected<T>()`.
|
||||
|
||||
|
||||
**Example**:
|
||||
|
||||
```swift
|
||||
class ClientImp: Client {
|
||||
@Injected var service: Service?
|
||||
}
|
||||
```
|
||||
|
||||
- seealso: `InjectedWeak`
|
||||
|
||||
*/
|
||||
@propertyWrapper
|
||||
public struct Injected<T>: _InjectedPropertyBox, AutoInjectedPropertyBox {
|
||||
let valueBox: NullableBox<T> = NullableBox(nil)
|
||||
|
||||
///Wrapped value.
|
||||
public var wrappedValue: T? {
|
||||
get {
|
||||
return valueBox.unboxed
|
||||
}
|
||||
set {
|
||||
guard (required && newValue != nil) || !required else {
|
||||
fatalError("Can not set required property to nil.")
|
||||
}
|
||||
valueBox.unboxed = newValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let required: Bool
|
||||
let didInject: (T) -> ()
|
||||
let tag: DependencyContainer.Tag?
|
||||
let overrideTag: Bool
|
||||
|
||||
public init(wrappedValue initialValue: T?) {
|
||||
self.init()
|
||||
}
|
||||
}
|
||||
#else
|
||||
/**
|
||||
Use this wrapper to identify _strong_ properties of the instance that should be
|
||||
auto-injected by `DependencyContainer`. Type T can be any type.
|
||||
|
||||
- warning: Do not define this property as optional or container will not be able to inject it.
|
||||
Instead define it with initial value of `Injected<T>()`.
|
||||
|
||||
**Example**:
|
||||
|
||||
```swift
|
||||
class ClientImp: Client {
|
||||
var service = Injected<Service>()
|
||||
}
|
||||
```
|
||||
|
||||
- seealso: `InjectedWeak`
|
||||
|
||||
*/
|
||||
public final class Injected<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox {
|
||||
|
||||
*/
|
||||
public struct Injected<T>: _InjectedPropertyBox, AutoInjectedPropertyBox {
|
||||
let valueBox: NullableBox<T> = NullableBox(nil)
|
||||
|
||||
///The type of wrapped property.
|
||||
public static var wrappedType: Any.Type {
|
||||
return T.self
|
||||
///Wrapped value.
|
||||
public var value: T? {
|
||||
return valueBox.unboxed
|
||||
}
|
||||
|
||||
///Wrapped value.
|
||||
public fileprivate(set) var value: T? {
|
||||
didSet {
|
||||
if let value = value { didInject(value) }
|
||||
let required: Bool
|
||||
let didInject: (T) -> ()
|
||||
let tag: DependencyContainer.Tag?
|
||||
let overrideTag: Bool
|
||||
|
||||
/// Returns a new wrapper with provided value.
|
||||
func setValue(_ value: T?) -> Injected {
|
||||
guard (required && value != nil) || !required else {
|
||||
fatalError("Can not set required property to nil.")
|
||||
}
|
||||
|
||||
return Injected(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public extension Injected {
|
||||
///The type of wrapped property.
|
||||
static var wrappedType: Any.Type {
|
||||
return T.self
|
||||
}
|
||||
|
||||
init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> ()) {
|
||||
self.value = value
|
||||
super.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
self.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
self.valueBox.unboxed = value
|
||||
}
|
||||
|
||||
init(required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> () = { _ in }) {
|
||||
self.required = required
|
||||
self.tag = tag?.dependencyTag
|
||||
self.overrideTag = overrideTag
|
||||
self.didInject = didInject
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,30 +208,24 @@ public final class Injected<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox
|
||||
- didInject: Block that will be called when concrete instance is injected in this property.
|
||||
Similar to `didSet` property observer. Default value does nothing.
|
||||
*/
|
||||
public convenience init(required: Bool = true, didInject: @escaping (T) -> () = { _ in }) {
|
||||
init(required: Bool = true, didInject: @escaping (T) -> () = { _ in }) {
|
||||
self.init(value: nil, required: required, tag: nil, overrideTag: false, didInject: didInject)
|
||||
}
|
||||
|
||||
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: @escaping (T) -> () = { _ in }) {
|
||||
init(required: Bool = true, tag: DependencyTagConvertible?, didInject: @escaping (T) -> () = { _ in }) {
|
||||
self.init(value: nil, required: required, tag: tag, overrideTag: true, didInject: didInject)
|
||||
}
|
||||
|
||||
public func resolve(_ container: DependencyContainer) throws {
|
||||
let resolved: T? = try super.resolve(with: container)
|
||||
value = resolved
|
||||
}
|
||||
|
||||
/// Returns a new wrapper with provided value.
|
||||
public func setValue(_ value: T?) -> Injected {
|
||||
guard (required && value != nil) || !required else {
|
||||
fatalError("Can not set required property to nil.")
|
||||
func resolve(_ container: DependencyContainer) throws {
|
||||
let resolved: T? = try self.resolve(with: container, tag: tag, overrideTag: overrideTag, required: required)
|
||||
valueBox.unboxed = resolved
|
||||
if let resolved = resolved {
|
||||
didInject(resolved)
|
||||
}
|
||||
|
||||
return Injected(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if swift(>=5.1)
|
||||
/**
|
||||
Use this wrapper to identify _weak_ properties of the instance that should be
|
||||
auto-injected by `DependencyContainer`. Type T should be a **class** type.
|
||||
@@ -175,7 +237,7 @@ public final class Injected<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox
|
||||
For that reason if you resolve instance that has a _weak_ auto-injected property this property
|
||||
will be released when `resolve` will complete.
|
||||
|
||||
Use `InjectedWeak<T>` to define one of two circular dependecies if another dependency is defined as `Injected<U>`.
|
||||
Use `InjectedWeak<T>` to define one of two circular dependencies if another dependency is defined as `Injected<U>`.
|
||||
This will prevent a retain cycle between resolved instances.
|
||||
|
||||
- warning: Do not define this property as optional or container will not be able to inject it.
|
||||
@@ -185,42 +247,124 @@ public final class Injected<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox
|
||||
|
||||
```swift
|
||||
class ServiceImp: Service {
|
||||
var client = InjectedWeak<Client>()
|
||||
@InjectedWeak var client: Client?
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- seealso: `Injected`
|
||||
|
||||
*/
|
||||
public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropertyBox {
|
||||
@propertyWrapper
|
||||
public struct InjectedWeak<T>: _InjectedPropertyBox, AutoInjectedPropertyBox {
|
||||
|
||||
//Only classes (means AnyObject) can be used as `weak` properties
|
||||
//but we can not make <T: AnyObject> because that will prevent using protocol as generic type
|
||||
//so we just rely on user reading documentation and passing AnyObject in runtime
|
||||
//also we will throw fatal error if type can not be casted to AnyObject during resolution.
|
||||
|
||||
///The type of wrapped property.
|
||||
public static var wrappedType: Any.Type {
|
||||
return T.self
|
||||
}
|
||||
|
||||
var valueBox: WeakBox<T>? = nil {
|
||||
didSet {
|
||||
if let value = value { didInject(value) }
|
||||
|
||||
let valueBox: WeakBox<T> = WeakBox(nil)
|
||||
|
||||
///Wrapped value.
|
||||
public var wrappedValue: T? {
|
||||
get {
|
||||
return valueBox.value
|
||||
}
|
||||
set {
|
||||
guard (required && newValue != nil) || !required else {
|
||||
fatalError("Can not set required property to nil.")
|
||||
}
|
||||
|
||||
valueBox.unboxed = newValue as AnyObject
|
||||
}
|
||||
}
|
||||
|
||||
let required: Bool
|
||||
let didInject: (T) -> ()
|
||||
let tag: DependencyContainer.Tag?
|
||||
let overrideTag: Bool
|
||||
|
||||
public init(wrappedValue initialValue: T?) {
|
||||
self.init()
|
||||
}
|
||||
}
|
||||
#else
|
||||
/**
|
||||
Use this wrapper to identify _weak_ properties of the instance that should be
|
||||
auto-injected by `DependencyContainer`. Type T should be a **class** type.
|
||||
Otherwise it will cause runtime exception when container will try to resolve the property.
|
||||
Use this wrapper to define one of two circular dependencies to avoid retain cycle.
|
||||
|
||||
- note: The only difference between `InjectedWeak` and `Injected` is that `InjectedWeak` uses
|
||||
_weak_ reference to store underlying value, when `Injected` uses _strong_ reference.
|
||||
For that reason if you resolve instance that has a _weak_ auto-injected property this property
|
||||
will be released when `resolve` will complete.
|
||||
|
||||
Use `InjectedWeak<T>` to define one of two circular dependencies if another dependency is defined as `Injected<U>`.
|
||||
This will prevent a retain cycle between resolved instances.
|
||||
|
||||
- warning: Do not define this property as optional or container will not be able to inject it.
|
||||
Instead define it with initial value of `InjectedWeak<T>()`.
|
||||
|
||||
**Example**:
|
||||
|
||||
```swift
|
||||
class ServiceImp: Service {
|
||||
var client = InjectedWeak<Client>()
|
||||
}
|
||||
```
|
||||
|
||||
- seealso: `Injected`
|
||||
|
||||
*/
|
||||
public struct InjectedWeak<T>: _InjectedPropertyBox, AutoInjectedPropertyBox {
|
||||
|
||||
//Only classes (means AnyObject) can be used as `weak` properties
|
||||
//but we can not make <T: AnyObject> because that will prevent using protocol as generic type
|
||||
//so we just rely on user reading documentation and passing AnyObject in runtime
|
||||
//also we will throw fatal error if type can not be casted to AnyObject during resolution.
|
||||
|
||||
let valueBox: WeakBox<T> = WeakBox(nil)
|
||||
|
||||
///Wrapped value.
|
||||
public var value: T? {
|
||||
return valueBox?.value
|
||||
return valueBox.value
|
||||
}
|
||||
|
||||
init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> ()) {
|
||||
self.valueBox = value.map(WeakBox.init)
|
||||
super.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
let required: Bool
|
||||
let didInject: (T) -> ()
|
||||
let tag: DependencyContainer.Tag?
|
||||
let overrideTag: Bool
|
||||
|
||||
|
||||
/// Returns a new wrapper with provided value.
|
||||
func setValue(_ value: T?) -> InjectedWeak {
|
||||
guard (required && value != nil) || !required else {
|
||||
fatalError("Can not set required property to nil.")
|
||||
}
|
||||
|
||||
return InjectedWeak(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public extension InjectedWeak {
|
||||
///The type of wrapped property.
|
||||
static var wrappedType: Any.Type {
|
||||
return T.self
|
||||
}
|
||||
|
||||
init(value: T?, required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> ()) {
|
||||
self.init(required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
self.valueBox.unboxed = value as AnyObject
|
||||
}
|
||||
|
||||
init(required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> () = { _ in }) {
|
||||
self.required = required
|
||||
self.tag = tag?.dependencyTag
|
||||
self.overrideTag = overrideTag
|
||||
self.didInject = didInject
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new wrapper for weak auto-injected property.
|
||||
|
||||
@@ -232,46 +376,28 @@ public final class InjectedWeak<T>: _InjectedPropertyBox<T>, AutoInjectedPropert
|
||||
- didInject: Block that will be called when concrete instance is injected in this property.
|
||||
Similar to `didSet` property observer. Default value does nothing.
|
||||
*/
|
||||
public convenience init(required: Bool = true, didInject: @escaping (T) -> () = { _ in }) {
|
||||
init(required: Bool = true, didInject: @escaping (T) -> () = { _ in }) {
|
||||
self.init(value: nil, required: required, tag: nil, overrideTag: false, didInject: didInject)
|
||||
}
|
||||
|
||||
public convenience init(required: Bool = true, tag: DependencyTagConvertible?, didInject: @escaping (T) -> () = { _ in }) {
|
||||
init(required: Bool = true, tag: DependencyTagConvertible?, didInject: @escaping (T) -> () = { _ in }) {
|
||||
self.init(value: nil, required: required, tag: tag, overrideTag: true, didInject: didInject)
|
||||
}
|
||||
|
||||
public func resolve(_ container: DependencyContainer) throws {
|
||||
let resolved: T? = try super.resolve(with: container)
|
||||
valueBox = resolved.map(WeakBox.init)
|
||||
}
|
||||
|
||||
/// Returns a new wrapper with provided value.
|
||||
public func setValue(_ value: T?) -> InjectedWeak {
|
||||
guard (required && value != nil) || !required else {
|
||||
fatalError("Can not set required property to nil.")
|
||||
func resolve(_ container: DependencyContainer) throws {
|
||||
let resolved: T? = try self.resolve(with: container, tag: tag, overrideTag: overrideTag, required: required)
|
||||
valueBox.unboxed = resolved as AnyObject
|
||||
if let resolved = resolved {
|
||||
didInject(resolved)
|
||||
}
|
||||
|
||||
return InjectedWeak(value: value, required: required, tag: tag, overrideTag: overrideTag, didInject: didInject)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class _InjectedPropertyBox<T> {
|
||||
protocol _InjectedPropertyBox {}
|
||||
|
||||
let required: Bool
|
||||
let didInject: (T) -> ()
|
||||
let tag: DependencyContainer.Tag?
|
||||
let overrideTag: Bool
|
||||
|
||||
init(required: Bool = true, tag: DependencyTagConvertible?, overrideTag: Bool, didInject: @escaping (T) -> () = { _ in }) {
|
||||
self.required = required
|
||||
self.tag = tag?.dependencyTag
|
||||
self.overrideTag = overrideTag
|
||||
self.didInject = didInject
|
||||
}
|
||||
|
||||
func resolve(with container: DependencyContainer) throws -> T? {
|
||||
let tag = overrideTag ? self.tag : container.context.tag
|
||||
extension _InjectedPropertyBox {
|
||||
func resolve<T>(with container: DependencyContainer, tag: DependencyContainer.Tag?, overrideTag: Bool, required: Bool) throws -> T? {
|
||||
let tag = overrideTag ? tag : container.context.tag
|
||||
do {
|
||||
container.context.key = container.context.key.tagged(with: tag)
|
||||
let key = DefinitionKey(type: T.self, typeOfArguments: Void.self, tag: tag?.dependencyTag)
|
||||
@@ -289,7 +415,7 @@ public class _InjectedPropertyBox<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private func resolve<U>(with container: DependencyContainer, key: DefinitionKey, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
|
||||
func resolve<U>(with container: DependencyContainer, key: DefinitionKey, builder: ((U) throws -> Any) throws -> Any) throws -> Any {
|
||||
return try container._resolve(key: key, builder: { definition throws -> Any in
|
||||
try builder(definition.weakFactory)
|
||||
})
|
||||
|
||||
@@ -61,7 +61,7 @@ public struct DefinitionKey: Hashable, CustomStringConvertible {
|
||||
}
|
||||
|
||||
///Dummy protocol to store definitions for different types in collection
|
||||
public protocol DefinitionType: class { }
|
||||
public protocol DefinitionType: AnyObject { }
|
||||
|
||||
/**
|
||||
`Definition<T, U>` describes how instances of type `T` should be created when this type is resolved by the `DependencyContainer`.
|
||||
@@ -206,7 +206,7 @@ public final class Definition<T, U>: DefinitionType {
|
||||
|
||||
//definitions for types that can be resolved by `forwardsTo` definition
|
||||
//can also be used to resolve self type and it's implementing types
|
||||
//this way container properly reuses previosly resolved instances
|
||||
//this way container properly reuses previously resolved instances
|
||||
//when there are several forwarded definitions
|
||||
//see testThatItReusesInstanceResolvedByTypeForwarding)
|
||||
for definition in forwardsTo.forwardsFrom {
|
||||
@@ -292,7 +292,7 @@ class DefinitionBuilder<T, U> {
|
||||
|
||||
typealias KeyDefinitionPair = (key: DefinitionKey, definition: _Definition)
|
||||
|
||||
/// Definitions are matched if they are registered for the same tag and thier factories accept the same number of runtime arguments.
|
||||
/// Definitions are matched if they are registered for the same tag and their factories accept the same number of runtime arguments.
|
||||
private func ~=(lhs: KeyDefinitionPair, rhs: KeyDefinitionPair) -> Bool {
|
||||
guard lhs.key.type == rhs.key.type else { return false }
|
||||
guard lhs.key.tag == rhs.key.tag else { return false }
|
||||
@@ -300,9 +300,9 @@ private func ~=(lhs: KeyDefinitionPair, rhs: KeyDefinitionPair) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
/// Returns key-defintion pairs with definitions able to resolve that type (directly or via type forwarding)
|
||||
/// Returns key-definition pairs with definitions able to resolve that type (directly or via type forwarding)
|
||||
/// and which tag matches provided key's tag or is nil if strictByTag is false.
|
||||
/// In the end filters defintions by type of runtime arguments.
|
||||
/// In the end filters definitions by type of runtime arguments.
|
||||
func filter(definitions _definitions: [KeyDefinitionPair], byKey key: DefinitionKey, strictByTag: Bool = false, byTypeOfArguments: Bool = false) -> [KeyDefinitionPair] {
|
||||
let definitions = _definitions
|
||||
.filter({ $0.key.type == key.type || $0.definition.doesImplements(type: key.type) })
|
||||
|
||||
+11
-4
@@ -40,6 +40,7 @@ public final class DependencyContainer {
|
||||
}
|
||||
|
||||
var autoInjectProperties: Bool
|
||||
var threadSafe: Bool
|
||||
internal(set) public var context: Context!
|
||||
var definitions = [DefinitionKey: _Definition]()
|
||||
var resolvedInstances = ResolvedInstances()
|
||||
@@ -63,6 +64,7 @@ public final class DependencyContainer {
|
||||
|
||||
- Parameters:
|
||||
- autoInjectProperties: Whether container should perform properties auto-injection. Default is `true`.
|
||||
- threadSafe: Whether container should be thread-safe. Default is `true`. You may want to disable it for better performance.
|
||||
- configBlock: A configuration block in which you typically put all you `register` calls.
|
||||
|
||||
- note: The `configBlock` is simply called at the end of the `init` to let you configure everything.
|
||||
@@ -82,8 +84,9 @@ public final class DependencyContainer {
|
||||
|
||||
- returns: A new DependencyContainer.
|
||||
*/
|
||||
public init(autoInjectProperties: Bool = true, configBlock: (DependencyContainer)->() = { _ in }) {
|
||||
public init(autoInjectProperties: Bool = true, threadSafe: Bool = true, configBlock: (DependencyContainer)->() = { _ in }) {
|
||||
self.autoInjectProperties = autoInjectProperties
|
||||
self.threadSafe = threadSafe
|
||||
configBlock(self)
|
||||
}
|
||||
|
||||
@@ -91,7 +94,7 @@ public final class DependencyContainer {
|
||||
Call this method to complete container setup. After container is bootstrapped
|
||||
you can not add or remove definitions. Trying to do so will cause runtime exception.
|
||||
You can completely reset container, after reset you can bootstrap it again.
|
||||
During bootsrap container will instantiate components registered with `EagerSingleton` scope.
|
||||
During bootstrap container will instantiate components registered with `EagerSingleton` scope.
|
||||
|
||||
- throws: `DipError` if failed to instantiate any component
|
||||
*/
|
||||
@@ -104,6 +107,10 @@ public final class DependencyContainer {
|
||||
}
|
||||
|
||||
func threadSafe<T>(_ closure: () throws -> T) rethrows -> T {
|
||||
guard threadSafe else {
|
||||
return try closure()
|
||||
}
|
||||
|
||||
lock.lock()
|
||||
defer { lock.unlock() }
|
||||
return try closure()
|
||||
@@ -291,7 +298,7 @@ extension DependencyContainer {
|
||||
for collaborator in _collaborators {
|
||||
//if container is already in a context resolving this type
|
||||
//it means that it has been already called to resolve this type,
|
||||
//so there is probably a cercular reference between containers.
|
||||
//so there is probably a circular reference between containers.
|
||||
//To break it skip this container
|
||||
if let context = collaborator.context, context.resolvingType == key.type && context.tag == key.tag { continue }
|
||||
|
||||
@@ -446,7 +453,7 @@ extension DependencyContainer: CustomStringConvertible {
|
||||
//MARK: - DependencyTagConvertible
|
||||
|
||||
/// Implement this protocol on your type if you want to use its instances as `DependencyContainer`'s tags.
|
||||
/// `DependencyContainer.Tag`, `String`, `Int` and any `RawRepresentable` with `RawType` of `String` or `Int` by default confrom to this protocol.
|
||||
/// `DependencyContainer.Tag`, `String`, `Int` and any `RawRepresentable` with `RawType` of `String` or `Int` by default conform to this protocol.
|
||||
public protocol DependencyTagConvertible {
|
||||
var dependencyTag: DependencyContainer.Tag { get }
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public enum DipError: Error, CustomStringConvertible {
|
||||
case ambiguousDefinitions(type: Any.Type, definitions: [DefinitionType])
|
||||
|
||||
/**
|
||||
Thrown by `resolve(tag:)` if resolved instance does not implemenet resolved type (i.e. when type-forwarding).
|
||||
Thrown by `resolve(tag:)` if resolved instance does not implement resolved type (i.e. when type-forwarding).
|
||||
|
||||
- parameters:
|
||||
- resolved: Resolved instance
|
||||
|
||||
@@ -81,7 +81,7 @@ extension DependencyContainer {
|
||||
|
||||
- parameters:
|
||||
- tag: The arbitrary tag to use to lookup definition.
|
||||
- builder: Generic closure that accepts generic factory and returns inctance created by that factory.
|
||||
- builder: Generic closure that accepts generic factory and returns instance created by that factory.
|
||||
|
||||
- throws: `DipError.DefinitionNotFound`, `DipError.AutoInjectionFailed`, `DipError.AmbiguousDefinitions`, `DipError.InvalidType`
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ extension DependencyContainer {
|
||||
}
|
||||
```
|
||||
|
||||
Though before you do so you should probably review your design and try to reduce number of depnedencies.
|
||||
Though before you do so you should probably review your design and try to reduce number of dependencies.
|
||||
*/
|
||||
public func register<T, U>(scope: ComponentScope, type: T.Type, tag: DependencyTagConvertible?, factory: @escaping (U) throws -> T, numberOfArguments: Int, autoWiringFactory: @escaping (DependencyContainer, Tag?) throws -> T) -> Definition<T, U> {
|
||||
let definition = DefinitionBuilder<T, U> {
|
||||
@@ -141,7 +141,7 @@ extension DependencyContainer {
|
||||
which factories accept any number of runtime arguments and are tagged with the same tag,
|
||||
passed to `resolve` method, or with no tag. Container will try to use these definitions
|
||||
to resolve a component one by one until one of them succeeds, starting with tagged definitions
|
||||
in order of decreasing their's factories number of arguments. If none of them succeds it will
|
||||
in order of decreasing their's factories number of arguments. If none of them succeeds it will
|
||||
throw an error. If it finds two definitions with the same number of arguments - it will throw
|
||||
an error.
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if (canImport(UIKit) || canImport(AppKit) || canImport(WatchKit)) && !SWIFT_PACKAGE
|
||||
#if (canImport(UIKit) || canImport(AppKit) || canImport(WatchKit))
|
||||
|
||||
extension DependencyContainer {
|
||||
///Containers that will be used to resolve dependencies of instances, created by stroyboards.
|
||||
|
||||
+9
-9
@@ -56,6 +56,13 @@ class Box<T> {
|
||||
}
|
||||
}
|
||||
|
||||
class NullableBox<T> {
|
||||
var unboxed: T?
|
||||
init(_ value: T?) {
|
||||
self.unboxed = value
|
||||
}
|
||||
}
|
||||
|
||||
protocol WeakBoxType {
|
||||
var unboxed: AnyObject? { get }
|
||||
}
|
||||
@@ -66,15 +73,8 @@ class WeakBox<T>: WeakBoxType {
|
||||
return unboxed as? T
|
||||
}
|
||||
|
||||
init(_ value: T) {
|
||||
#if _runtime(_ObjC)
|
||||
weak var value: AnyObject? = value as AnyObject
|
||||
#else
|
||||
weak var value: AnyObject? = value as? AnyObject
|
||||
#endif
|
||||
guard value != nil else {
|
||||
fatalError("Can not store weak reference to not a class instance (\(T.self))")
|
||||
}
|
||||
init(_ value: T?) {
|
||||
weak var value: AnyObject? = value as AnyObject
|
||||
self.unboxed = value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,16 +25,44 @@
|
||||
import XCTest
|
||||
@testable import Dip
|
||||
|
||||
private protocol Server: class {
|
||||
private protocol Server: AnyObject {
|
||||
var client: Client! {get}
|
||||
var anotherClient: Client! {get set}
|
||||
}
|
||||
|
||||
private protocol Client: class {
|
||||
private protocol Client: AnyObject {
|
||||
var server: Server? {get}
|
||||
var anotherServer: Server! {get set}
|
||||
}
|
||||
|
||||
#if swift(>=5.1)
|
||||
private class ServerImp: Server {
|
||||
|
||||
@InjectedWeak(didInject: { _ in
|
||||
AutoInjectionTests.clientDidInjectCalled = true
|
||||
}) var client: Client!
|
||||
|
||||
@InjectedWeak(required: false) var _optionalProperty: AnyObject?
|
||||
|
||||
weak var anotherClient: Client!
|
||||
}
|
||||
|
||||
private class ClientImp: Client {
|
||||
|
||||
@Injected(didInject: { _ in
|
||||
AutoInjectionTests.serverDidInjectCalled = true
|
||||
}) var server: Server
|
||||
|
||||
@Injected(required: false) var _optionalProperty: AnyObject?
|
||||
|
||||
@Injected(tag: "tagged") var taggedServer: Server
|
||||
@Injected(tag: nil) var nilTaggedServer: Server
|
||||
|
||||
var anotherServer: Server!
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
private class ServerImp: Server {
|
||||
|
||||
var _client = InjectedWeak<Client>() { _ in
|
||||
@@ -67,7 +95,18 @@ private class ClientImp: Client {
|
||||
var taggedServer = Injected<Server>(tag: "tagged")
|
||||
var nilTaggedServer = Injected<Server>(tag: nil)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if swift(>=5.1)
|
||||
private class Obj1 {
|
||||
@InjectedWeak var obj2: Obj2?
|
||||
@Injected var obj3: Obj3?
|
||||
}
|
||||
|
||||
private class Obj2 {
|
||||
@Injected var obj1: Obj1?
|
||||
}
|
||||
#else
|
||||
private class Obj1 {
|
||||
let obj2 = InjectedWeak<Obj2>()
|
||||
let obj3 = Injected<Obj3>()
|
||||
@@ -76,6 +115,7 @@ private class Obj1 {
|
||||
private class Obj2 {
|
||||
let obj1 = Injected<Obj1>()
|
||||
}
|
||||
#endif
|
||||
|
||||
private class Obj3 {
|
||||
|
||||
@@ -108,10 +148,18 @@ class AutoInjectionTests: XCTestCase {
|
||||
|
||||
func testThatItResolvesInheritedDependencies() {
|
||||
class ServerImp2: ServerImp {
|
||||
#if swift(>=5.1)
|
||||
@InjectedWeak(didInject: { _ in
|
||||
XCTAssertTrue(AutoInjectionTests.serverDidInjectCalled, "Inherited properties should be resolved first")
|
||||
}) var client2: Client?
|
||||
#else
|
||||
var _client2 = InjectedWeak<Client>() { _ in
|
||||
XCTAssertTrue(AutoInjectionTests.serverDidInjectCalled, "Inherited properties should be resolved first")
|
||||
}
|
||||
var client2: Client? { return _client2.value }
|
||||
var client2: Client? {
|
||||
return _client2.value
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
container.register { ServerImp2() as Server }
|
||||
@@ -124,6 +172,28 @@ class AutoInjectionTests: XCTestCase {
|
||||
XCTAssertTrue(client === server?.client2)
|
||||
}
|
||||
|
||||
func testThatItCanSetInjectedProperty() {
|
||||
container.register { ServerImp() as Server }
|
||||
container.register { ClientImp() as Client }
|
||||
|
||||
let client = (try! container.resolve() as Client) as! ClientImp
|
||||
let server = client.server as! ServerImp
|
||||
|
||||
let newServer = ServerImp()
|
||||
let newClient = ClientImp()
|
||||
#if swift(>=5.1)
|
||||
client.server = newServer
|
||||
server.client = newClient
|
||||
#else
|
||||
client._server = client._server.setValue(newServer)
|
||||
server._client = server._client.setValue(newClient)
|
||||
#endif
|
||||
|
||||
XCTAssertTrue(client.server === newServer)
|
||||
XCTAssertTrue(server.client === newClient)
|
||||
}
|
||||
|
||||
|
||||
func testThatItThrowsErrorIfFailsToAutoInjectDependency() {
|
||||
container.register { ClientImp() as Client }
|
||||
|
||||
@@ -209,11 +279,19 @@ class AutoInjectionTests: XCTestCase {
|
||||
let obj2 = try! container.resolve() as Obj2
|
||||
|
||||
//then
|
||||
XCTAssertTrue(obj2 === obj2.obj1.value!.obj2.value!,
|
||||
#if swift(>=5.1)
|
||||
XCTAssertTrue(obj2 === obj2.obj1!.obj2!,
|
||||
"Auto-injected instance should be reused on next auto-injection")
|
||||
|
||||
XCTAssertTrue(obj2.obj1.value! === obj2.obj1.value!.obj3.value!.obj1,
|
||||
XCTAssertTrue(obj2.obj1! === obj2.obj1!.obj3!.obj1,
|
||||
"Auto-injected instance should be reused on next resolve")
|
||||
#else
|
||||
XCTAssertTrue(obj2 === obj2.obj1.value!.obj2.value!,
|
||||
"Auto-injected instance should be reused on next auto-injection")
|
||||
|
||||
XCTAssertTrue(obj2.obj1.value! === obj2.obj1.value!.obj3.value!.obj1,
|
||||
"Auto-injected instance should be reused on next resolve")
|
||||
#endif
|
||||
}
|
||||
|
||||
func testThatThereIsNoRetainCycleBetweenAutoInjectedCircularDependencies() {
|
||||
@@ -274,7 +352,11 @@ class AutoInjectionTests: XCTestCase {
|
||||
let client = try! container.resolve() as Client
|
||||
|
||||
//then
|
||||
#if swift(>=5.1)
|
||||
let taggedServer = (client as! ClientImp).taggedServer!
|
||||
#else
|
||||
let taggedServer = (client as! ClientImp).taggedServer.value!
|
||||
#endif
|
||||
let server = client.server!
|
||||
|
||||
//server and tagged server should be resolved as different instances
|
||||
@@ -293,7 +375,11 @@ class AutoInjectionTests: XCTestCase {
|
||||
let client = try! container.resolve(tag: "tagged") as Client
|
||||
|
||||
//then
|
||||
#if swift(>=5.1)
|
||||
let taggedServer = (client as! ClientImp).taggedServer!
|
||||
#else
|
||||
let taggedServer = (client as! ClientImp).taggedServer.value!
|
||||
#endif
|
||||
let server = client.server!
|
||||
|
||||
//server and tagged server should be resolved as the same instance
|
||||
@@ -314,8 +400,13 @@ class AutoInjectionTests: XCTestCase {
|
||||
let client = try! container.resolve(tag: "otherTag") as Client
|
||||
|
||||
//then
|
||||
#if swift(>=5.1)
|
||||
let taggedServer = (client as! ClientImp).taggedServer!
|
||||
let nilTaggedServer = (client as! ClientImp).nilTaggedServer!
|
||||
#else
|
||||
let taggedServer = (client as! ClientImp).taggedServer.value!
|
||||
let nilTaggedServer = (client as! ClientImp).nilTaggedServer.value!
|
||||
#endif
|
||||
let server = client.server!
|
||||
|
||||
//server and tagged server should be resolved as different instances
|
||||
@@ -397,7 +488,7 @@ class AutoInjectionTests: XCTestCase {
|
||||
XCTAssertNil(server)
|
||||
}
|
||||
|
||||
func testThatItAutoInjectsWhenOverridenInDefinition() {
|
||||
func testThatItAutoInjectsWhenOverriddenInDefinition() {
|
||||
let container = DependencyContainer(autoInjectProperties: false)
|
||||
container.register { ServerImp() as Server }
|
||||
container.register { ClientImp() as Client }
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
import XCTest
|
||||
@testable import Dip
|
||||
|
||||
private protocol Service: class { }
|
||||
private protocol Service: AnyObject { }
|
||||
private class ServiceImp1: Service { }
|
||||
private class ServiceImp2: Service { }
|
||||
private class ServiceImp3 {}
|
||||
|
||||
private protocol AutoWiredClient: class {
|
||||
private protocol AutoWiredClient: AnyObject {
|
||||
var service1: Service! { get set }
|
||||
var service2: Service! { get set }
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
import XCTest
|
||||
@testable import Dip
|
||||
|
||||
private protocol Service: class {}
|
||||
private protocol Service: AnyObject {}
|
||||
private class ServiceImp1: Service {}
|
||||
private class ServiceImp2: Service {}
|
||||
|
||||
@@ -316,7 +316,7 @@ class ComponentScopeTests: XCTestCase {
|
||||
container.register(service, type: Service.self)
|
||||
|
||||
//when
|
||||
//resolve and realease reight away
|
||||
//resolve and release right away
|
||||
_ = try? container.resolve() as ServiceImp1
|
||||
|
||||
//then
|
||||
|
||||
@@ -100,7 +100,7 @@ class DefinitionTests: XCTestCase {
|
||||
XCTAssertFalse(blockCalled)
|
||||
}
|
||||
|
||||
func testThatItRegisteresOptionalTypesAsForwardedTypes() {
|
||||
func testThatItRegistersOptionalTypesAsForwardedTypes() {
|
||||
let def = Definition<Service, ()>(scope: .unique) { ServiceImp() as Service }
|
||||
|
||||
XCTAssertTrue(def.implementingTypes.contains(where: { $0 == Service?.self }))
|
||||
|
||||
@@ -25,14 +25,14 @@
|
||||
import XCTest
|
||||
@testable import Dip
|
||||
|
||||
private protocol Service: class { }
|
||||
private protocol Service: AnyObject { }
|
||||
private class ServiceImp1: Service { }
|
||||
private class ServiceImp2: Service { }
|
||||
|
||||
private protocol Server: class {
|
||||
private protocol Server: AnyObject {
|
||||
var client: Client! { get }
|
||||
}
|
||||
private protocol Client: class {
|
||||
private protocol Client: AnyObject {
|
||||
var server: Server! { get }
|
||||
}
|
||||
|
||||
|
||||
@@ -164,10 +164,10 @@ class DipUITests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
protocol SomeService: class {
|
||||
protocol SomeService: AnyObject {
|
||||
var delegate: SomeServiceDelegate? { get set }
|
||||
}
|
||||
protocol SomeServiceDelegate: class { }
|
||||
protocol SomeServiceDelegate: AnyObject { }
|
||||
class SomeServiceImp: SomeService {
|
||||
weak var delegate: SomeServiceDelegate?
|
||||
init(delegate: SomeServiceDelegate) {
|
||||
@@ -176,10 +176,10 @@ class SomeServiceImp: SomeService {
|
||||
init(){}
|
||||
}
|
||||
|
||||
protocol OtherService: class {
|
||||
protocol OtherService: AnyObject {
|
||||
var delegate: OtherServiceDelegate? { get set }
|
||||
}
|
||||
protocol OtherServiceDelegate: class {}
|
||||
protocol OtherServiceDelegate: AnyObject {}
|
||||
class OtherServiceImp: OtherService {
|
||||
weak var delegate: OtherServiceDelegate?
|
||||
init(delegate: OtherServiceDelegate){
|
||||
@@ -189,7 +189,7 @@ class OtherServiceImp: OtherService {
|
||||
}
|
||||
|
||||
|
||||
protocol SomeScreen: class {
|
||||
protocol SomeScreen: AnyObject {
|
||||
var someService: SomeService? { get set }
|
||||
var otherService: OtherService? { get set }
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ class RuntimeArgumentsTests: XCTestCase {
|
||||
|
||||
//Due to incomplete implementation of SE-0054 (bug: https://bugs.swift.org/browse/SR-2143)
|
||||
//registering definition with T? and T! arguments types will produce two different definitions
|
||||
//but when argement of T! will be passed to `resolve` method it will be transformed to T?
|
||||
//but when argument of T! will be passed to `resolve` method it will be transformed to T?
|
||||
//and wrong definition will be used
|
||||
//When fixed using T? and T! should not register two different definitions
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
import XCTest
|
||||
@testable import Dip
|
||||
|
||||
private protocol Server: class {
|
||||
private protocol Server: AnyObject {
|
||||
var client: Client! { get set }
|
||||
}
|
||||
|
||||
private protocol Client: class {
|
||||
private protocol Client: AnyObject {
|
||||
var server: Server { get }
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
import XCTest
|
||||
@testable import Dip
|
||||
|
||||
private protocol Service: class { }
|
||||
private protocol ForwardedType: class { }
|
||||
private protocol Service: AnyObject { }
|
||||
private protocol ForwardedType: AnyObject { }
|
||||
#if os(Linux)
|
||||
private class ServiceImp1: Service, ForwardedType { }
|
||||
private class ServiceImp2: Service, ForwardedType { }
|
||||
@@ -136,7 +136,7 @@ class TypeForwardingTests: XCTestCase {
|
||||
resolveDependenciesCalled = true
|
||||
|
||||
//when
|
||||
//resolving via type-forawrding for tag different then tag for original definition
|
||||
//resolving via type-forwarding for tag different then tag for original definition
|
||||
let forwardType = try container.resolve(tag: "tag") as ForwardedType
|
||||
let anyForwardType = try container.resolve(ForwardedType.self, tag: "tag") as! ForwardedType
|
||||
|
||||
|
||||
Reference in New Issue
Block a user