Compare commits

...

14 Commits

Author SHA1 Message Date
Ilya Puchka a1ece4b0ab Merge pull request #126 from AliSoftware/release/5.0.2
Release 5.0.2
2016-10-09 11:33:26 +02:00
Ilya Puchka 0b00e13e00 added hasPrefix method for Linux 2016-10-09 00:34:11 +02:00
Ilya Puchka 4aec626a1f bumped version to 5.0.2 2016-10-08 00:28:05 +02:00
Ilya Puchka d477392deb building against 3.0-RELEASE on Travis on Linux 2016-10-08 00:27:51 +02:00
Ilya Puchka 3b23dc1a6f updated README and CHANGELOG 2016-10-08 00:27:08 +02:00
Ilya Puchka 1d7d0052bf fixed logging 2016-10-07 22:47:07 +02:00
Ilya Puchka b1fee5c1db Merge pull request #125 from AliSoftware/features/swift-3-fixes
Fixed Swift 3 issues
2016-10-07 22:13:41 +02:00
Ilya Puchka e19b65d9c2 fixed issues with reflection of objectes with IUO properties 2016-10-07 19:19:05 +02:00
Ilya Puchka 86bb28da14 Merge branch 'hotfix/pod-fix' into develop 2016-09-16 12:13:30 +02:00
Ilya Puchka e4545e3ed3 Merge pull request #124 from AliSoftware/hotfix/pod-fix
Pod hotfix
2016-09-16 12:13:03 +02:00
Ilya Puchka 52455e663c bumped version to 5.0.1 2016-09-15 01:37:25 +02:00
Ilya Puchka 7a10d1e46e fixed linting podspec 2016-09-15 01:00:34 +02:00
Ilya Puchka e95df85503 Update README.md 2016-09-11 21:18:03 +02:00
Ilya Puchka a028c05271 Merge branch 'release/5.0.0' into develop 2016-09-11 20:48:56 +02:00
14 changed files with 135 additions and 127 deletions
+1
View File
@@ -0,0 +1 @@
3.0
+6 -8
View File
@@ -1,7 +1,3 @@
env:
global:
- MODULE_NAME=Dip
matrix:
allow_failures:
- os: linux
@@ -12,11 +8,13 @@ matrix:
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme Dip -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV 1080p,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- set -o pipefail && xcodebuild -workspace Dip.xcworkspace -scheme Dip -sdk watchsimulator -destination 'platform=watchOS Simulator,name=Apple Watch - 38mm,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty - c
- set -o pipefail && xcodebuild test -workspace Dip.xcworkspace -scheme DipSampleApp -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- pod lib lint --quick
- pod spec lint
- carthage build --no-skip-current
os: osx
osx_image: xcode8
language: objective-c
before_install:
- gem install cocoapods --version 1.1.0.rc.2 --no-document
- script:
- swift build --clean && swift build && swift test
os: linux
@@ -26,11 +24,11 @@ matrix:
before_install:
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
- cd ..
- export SWIFT_VERSION=swift-DEVELOPMENT-SNAPSHOT-2016-09-07-a
- wget https://swift.org/builds/development/ubuntu1404/$SWIFT_VERSION/$SWIFT_VERSION-ubuntu14.04.tar.gz
- export SWIFT_VERSION=swift-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 $MODULE_NAME
- cd Dip
notifications:
email: false
+11
View File
@@ -1,5 +1,16 @@
# CHANGELOG
## 5.0.2
#### Fixed
* Fixed Swift 3 issues related to reflection and IUO
[#125](https://github.com/AliSoftware/Dip/issues/125), [@ilyapuchka](https://github.com/ilyapuchka)
## 5.0.1
This release is the same as 5.0.0 and only fixes CocoaPods speck pushed to trunk without macOS, tvOS and watchOS deployment targets. Please use this release instead of 5.0.0 if you integrate Dip via Cocoapods.
## 5.0.0
* Migrated to Swift 3.0
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Dip"
s.version = "5.0.0"
s.version = "5.0.2"
s.summary = "Dependency Injection for Swift made easy."
s.description = <<-DESC
+4 -2
View File
@@ -287,6 +287,7 @@
0903B3691C161544002241C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
"CODE_SIGN_IDENTITY[sdk=*]" = "";
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
@@ -310,6 +311,7 @@
0903B36A1C161544002241C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
"CODE_SIGN_IDENTITY[sdk=*]" = "";
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
@@ -377,7 +379,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 5.0.0;
CURRENT_PROJECT_VERSION = 5.0.2;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -432,7 +434,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 5.0.0;
CURRENT_PROJECT_VERSION = 5.0.2;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -113,10 +113,7 @@ class ServerImp: Server {
weak var client: ServerClient?
}
//There is currently a bug in Swift that causes runtime crash
//when trying to auto-inject not-NSObject weak property.
//https://bugs.swift.org/browse/SR-2144
class ServerClientImp: NSObject, ServerClient {
class ServerClientImp: ServerClient {
var server: Server?
init(server: Server) {
@@ -149,10 +146,7 @@ class InjectedServerImp: Server {
var client: ServerClient? { return injectedClient.value }
}
//There is currently a bug in Swift that causes runtime crash
//when trying to auto-inject not-NSObject weak property.
//https://bugs.swift.org/browse/SR-2144
class InjectedClientImp: NSObject, ServerClient {
class InjectedClientImp: ServerClient {
private var injectedServer = Injected<Server>()
var server: Server? { get { return injectedServer.value } }
}
+69 -62
View File
@@ -5,8 +5,8 @@
[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![License](https://img.shields.io/cocoapods/l/Dip.svg?style=flat)](http://cocoapods.org/pods/Dip)
[![Platform](https://img.shields.io/cocoapods/p/Dip.svg?style=flat)](http://cocoapods.org/pods/Dip)
[![Swift Version](https://img.shields.io/badge/Linux-compatible-4BC51D.svg?style=flat)](https://developer.apple.com/swift)
[![Swift Version](https://img.shields.io/badge/Swift-2.2-3.0-F16D39.svg?style=flat)](https://developer.apple.com/swift)
[![Swift Version](https://img.shields.io/badge/Swift-2.2--3.0-F16D39.svg?style=flat)](https://developer.apple.com/swift)
[![Swift Version](https://img.shields.io/badge/Linux-3.0--RELEASE-4BC51D.svg?style=flat)](https://developer.apple.com/swift)
![Animated Dipping GIF](cinnamon-pretzels-caramel-dipping.gif)
_Photo courtesy of [www.kevinandamanda.com](http://www.kevinandamanda.com/recipes/appetizer/homemade-soft-cinnamon-sugar-pretzel-bites-with-salted-caramel-dipping-sauce.html)_
@@ -17,46 +17,12 @@ _Photo courtesy of [www.kevinandamanda.com](http://www.kevinandamanda.com/recipe
It's aimed to be as simple as possible yet provide rich functionality usual for DI containers on other platforms. It's inspired by `.NET`'s [Unity Container](https://msdn.microsoft.com/library/ff647202.aspx) and other DI containers.
* You start by creating `let container = DependencyContainer()` and **registering your dependencies, by associating a _protocol_ or _type_ to a `factory`**.
* Then you can call `container.resolve()` to **resolve an instance of _protocol_ or _type_** using that `DependencyContainer`.
* 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 - checkout [Dip-UI](https://github.com/AliSoftware/Dip-UI) extensions.
## Documentation & Usage Examples
Dip is completely [documented](http://cocoadocs.org/docsets/Dip/5.0.0/) and comes with a Playground that lets you try all its features and become familiar with API. You can find it in `Dip.xcworkspace`.
> Note: it may happen that you will need to build Dip framework before playground will be able to use it. For that select `Dip-iOS` scheme and build.
You can find bunch of usage examples in a [wiki](../../wiki).
If your are using [VIPER](https://www.objc.io/issues/13-architecture/viper/) architecture - [here](https://github.com/ilyapuchka/VIPER-SWIFT) is VIPER demo app that uses Dip instead of manual dependency injection.
There are also several blog posts that describe how to use Dip and some of its implementation details:
- [IoC container in Swift](http://ilya.puchka.me/ioc-container-in-swift/)
- [IoC container in Swift. Circular dependencies and auto-injection](http://ilya.puchka.me/ioc-container-in-swift-circular-dependencies-and-auto-injection/)
- [Dependency injection with Dip](http://ilya.puchka.me/dependency-injecinjection-with-dip/)
File an issue if you have any question.
## Features
- **[Scopes](../../wiki/scopes)**. Dip supports 5 different scopes (or life cycle strategies): _Unique_, _Shared_, _Singleton_, _EagerSingleton_, _WeakSingleton_;
- **[Named definitions](../../wiki/named-definitions)**. You can register different factories for the same protocol or type by registering them with [tags]();
- **[Runtime arguments](../../wiki/runtime-arguments)**. You can register factories that accept up to 6 runtime arguments;
- **[Circular dependencies](../../wiki/circular-dependencies)**. Dip can resolve circular dependencies;
- **[Auto-wiring](../../wiki/auto-wiring)** & **[Auto-injection](../../wiki/auto-injection)**. Dip can infer your components' dependencies injected in constructor and automatically resolve them as well as dependencies injected with properties.
- **[Resolving optionals](../../wiki/resolving-optionals)**. Dip is able to resolve constructor or property dependencies defined as optionals.
- **[Type forwarding](../../wiki/type-forwarding)**. You can register the same factory to resolve different types.
- **[Storyboards integration](../../wiki/storyboards-integration)**. You can easily use Dip along with storyboards and Xibs without ever referencing container in your view controller's code;
- **Weakly typed components**. Dip can resolve weak types when they are unknown at compile time.
- **[Easy configuration](../../wiki/containers-collaboration)**. No complex container hierarchy, no unneeded functionality;
- **Thread safety**. Registering and resolving components is thread safe;
- **Helpful error messages and configuration validation**. You can validate your container configuration. If something can not be resolved at runtime Dip throws an error that completely describes the issue;
## Basic usage
<details>
<summary>Basic usage</summary>
```swift
import Dip
@@ -82,7 +48,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
```
## More sophisticated example
</details>
<details>
<summary>More sophisticated example</summary>
```swift
import Dip
@@ -100,6 +69,9 @@ extension DependencyContainer {
static func configure() -> DependencyContainer {
return DependencyContainer { container in
unowned let container = container
DependencyContainer.uiContainers = [container]
container.register(tag: "ViewController") { ViewController() }
.resolvingProperties { container, controller in
controller.animationsFactory = try container.resolve() as AnimatonsFactory
@@ -137,49 +109,84 @@ class ViewController {
```
</details>
## Documentation & Usage Examples
Dip is completely [documented](http://cocoadocs.org/docsets/Dip/5.0.0/) and comes with a Playground that lets you try all its features and become familiar with API. You can find it in `Dip.xcworkspace`.
> Note: it may happen that you will need to build Dip framework before playground will be able to use it. For that select `Dip` scheme and build for iPhone Simulator.
You can find bunch of usage examples and usfull tips in a [wiki](../../wiki).
If your are using [VIPER](https://www.objc.io/issues/13-architecture/viper/) architecture - [here](https://github.com/ilyapuchka/VIPER-SWIFT) is VIPER demo app that uses Dip instead of manual dependency injection.
There are also several blog posts that describe how to use Dip and some of its implementation details:
- [IoC container in Swift](http://ilya.puchka.me/ioc-container-in-swift/)
- [IoC container in Swift. Circular dependencies and auto-injection](http://ilya.puchka.me/ioc-container-in-swift-circular-dependencies-and-auto-injection/)
- [Dependency injection with Dip](http://ilya.puchka.me/dependency-injecinjection-with-dip/)
File an issue if you have any question. Pull requests are warmly welcome too.
## Features
- **[Scopes](../../wiki/scopes)**. Dip supports 5 different scopes (or life cycle strategies): _Unique_, _Shared_, _Singleton_, _EagerSingleton_, _WeakSingleton_;
- **[Auto-wiring](../../wiki/auto-wiring)** & **[Auto-injection](../../wiki/auto-injection)**. Dip can infer your components' dependencies injected in constructor and automatically resolve them as well as dependencies injected with properties.
- **[Resolving optionals](../../wiki/resolving-optionals)**. Dip is able to resolve constructor or property dependencies defined as optionals.
- **[Type forwarding](../../wiki/type-forwarding)**. You can register the same factory to resolve different types implemeted by a single class.
- **[Circular dependencies](../../wiki/circular-dependencies)**. Dip will be able to resolve circular dependencies if you will follow some simple rules;
- **[Storyboards integration](../../wiki/storyboards-integration)**. You can easily use Dip along with storyboards and Xibs without ever referencing container in your view controller's code;
- **[Named definitions](../../wiki/named-definitions)**. You can register different factories for the same protocol or type by registering them with [tags]();
- **[Runtime arguments](../../wiki/runtime-arguments)**. You can register factories that accept up to 6 runtime arguments (and extend it if you need);
- **[Easy configuration](../../wiki/containers-collaboration)** & **Code generation**. No complex containers hierarchy, no unneeded functionality. Tired of writing all registrations by hand? There is a [cool code generator](https://github.com/ilyapuchka/dipgen) that will create them for you. The only thing you need is to annotate your code with some comments.
- **Weakly typed components**. Dip can resolve "weak" types when they are unknown at compile time.
- **Thread safety**. Registering and resolving components is thread safe;
- **Helpful error messages and configuration validation**. You can validate your container configuration. If something can not be resolved at runtime Dip throws an error that completely describes the issue;
## Installation
Since version 5.0.0 Dip is built with Swift 3.0. For Swift 2.2-2.3 compatible version use "swift2.3" branch.
Dip is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile:
You can install Dip using your favorite dependency manager:
<details>
<summary>CocoaPods</summary>
```ruby
pod "Dip"
```
> You need at least 1.1.0.rc.2 version of CocoaPods.
If you use [Carthage](https://github.com/Carthage/Carthage) add this line to your Cartfile:
</details>
<details>
<summary>Carthage</summary>
```
github "AliSoftware/Dip"
```
If you use [Swift Package Manager](https://swift.org/package-manager/) add Dip as dependency to you `Package.swift`:
</details>
<details>
<summary>Swift Package Manager</summary>
```swift
let package = Package(
name: "MyPackage",
dependencies: [
.Package(url: "https://github.com/AliSoftware/Dip.git", "5.0.0")
]
)
.Package(url: "https://github.com/AliSoftware/Dip", majorVersion: 5, minor: 0)
```
</details>
## Running tests
On OSX you can run tests from Xcode. On Linux you need to have Swift Package Manager installed and use it to build and run tests:
```
cd Dip
swift build && swift test
```
> Note: Swift Package Manager is destributed with Swift development snapshots only, so it builds packages using Swift 3. To build Dip you will need to build it with Swift 2.2, for that you need to set [`$SWIFT_EXEC`](https://github.com/apple/swift-package-manager#choosing-swift-version) environment variable.
On OSX you can run tests from Xcode. On Linux you need to have Swift Package Manager installed and use it to build and run tests using this command: `swift build --clean && swift build && swift test`
## Credits
This library has been created by [**Olivier Halligon**](olivier@halligon.net).
I'd also like to thank [**Ilya Puchka**](https://twitter.com/ilyapuchka) for his big contribution to it, as he added a lot of great features to it.
This library has been created by [**Olivier Halligon**](olivier@halligon.net) and is maintained by [**Ilya Puchka**](https://twitter.com/ilyapuchka).
**Dip** is available under the **MIT license**. See the `LICENSE` file for more info.
+2
View File
@@ -43,6 +43,8 @@ extension DependencyContainer {
}
private func resolveChild(child: Mirror.Child) throws {
//HOTFIX for https://bugs.swift.org/browse/SR-2282
guard !String(describing: type(of: child.value)).hasPrefix("ImplicitlyUnwrappedOptional") else { return }
guard let injectedPropertyBox = child.value as? AutoInjectedPropertyBox else { return }
let contextKey = DefinitionKey(type: type(of: injectedPropertyBox).wrappedType, typeOfArguments: Void.self, tag: context.tag)
+13 -4
View File
@@ -22,15 +22,16 @@
// THE SOFTWARE.
//
public enum LogLevel {
case Verbose
case Errors
public enum LogLevel: Int {
case None
case Errors
case Verbose
}
public var logLevel: LogLevel = .Errors
func log(_ logLevel: LogLevel, _ message: Any) {
guard case logLevel = Dip.logLevel else { return }
guard logLevel.rawValue <= Dip.logLevel.rawValue else { return }
print(message)
}
@@ -117,6 +118,14 @@ extension Collection where Index: Comparable, Self.Indices.Index == Index {
}
#if os(Linux)
extension String {
public func hasPrefix(_ prefix: String) -> Bool {
return prefix ==
String(self.characters.prefix(prefix.characters.count))
}
}
import Glibc
class RecursiveLock {
private var _lock = _initializeRecursiveMutex()
+8 -8
View File
@@ -26,13 +26,13 @@ import XCTest
@testable import Dip
private protocol Server: class {
weak var client: Client? {get}
var anotherClient: Client? {get set}
weak var client: Client! {get}
var anotherClient: Client! {get set}
}
private protocol Client: class {
var server: Server? {get}
var anotherServer: Server? {get set}
var server: Server! {get}
var anotherServer: Server! {get set}
}
private class ServerImp: Server {
@@ -41,11 +41,11 @@ private class ServerImp: Server {
AutoInjectionTests.clientDidInjectCalled = true
}
var client: Client? {
var client: Client! {
return _client.value
}
weak var anotherClient: Client?
weak var anotherClient: Client!
weak var _optionalProperty = InjectedWeak<AnyObject>(required: false)
}
@@ -56,11 +56,11 @@ private class ClientImp: Client {
AutoInjectionTests.serverDidInjectCalled = true
}
var server: Server? {
var server: Server! {
return _server.value
}
var anotherServer: Server?
var anotherServer: Server!
var _optionalProperty = Injected<AnyObject>(required: false)
+4 -4
View File
@@ -31,13 +31,13 @@ private class ServiceImp2: Service { }
private class ServiceImp3 {}
private protocol AutoWiredClient: class {
var service1: Service? { get set }
var service2: Service? { get set }
var service1: Service! { get set }
var service2: Service! { get set }
}
private class AutoWiredClientImp: AutoWiredClient {
var service1: Service?
var service2: Service?
var service1: Service!
var service2: Service!
init(service1: Service?, service2: ServiceImp2) {
self.service1 = service1
+11 -27
View File
@@ -30,10 +30,10 @@ private class ServiceImp1: Service { }
private class ServiceImp2: Service { }
private protocol Server: class {
weak var client: Client? { get }
weak var client: Client! { get }
}
private protocol Client: class {
var server: Server? { get }
var server: Server! { get }
}
class ResolvableService: Service, Resolvable {
@@ -483,8 +483,8 @@ class DipTests: XCTestCase {
func testThatItResolvesCircularDependencies() {
class ResolvableServer: Server, Resolvable {
weak var client: Client?
weak var secondClient: Client?
weak var client: Client!
weak var secondClient: Client!
init(client: Client) {
self.client = client
@@ -505,17 +505,9 @@ class DipTests: XCTestCase {
}
//Due to a bug in Swift 3 Mirror fails if weak property is not NSObject
//https://bugs.swift.org/browse/SR-2144
class ResolvableClient: NSObject, Client, Resolvable {
var server: Server?
var secondServer: Server?
#if os(Linux)
init() {}
#else
override init() { super.init() }
#endif
class ResolvableClient: Client, Resolvable {
var server: Server!
var secondServer: Server!
var didResolveDependenciesCalled = false
@@ -698,21 +690,13 @@ extension DipTests {
func testThatCollaboratingContainersReuseInstancesResolvedByAnotherContainer() {
//given
class ServerImp: Server {
weak var client: Client?
weak var client: Client!
init(client: Client) { self.client = client }
}
//Due to a bug in Swift 3 Mirror fails if weak property is not NSObject
//https://bugs.swift.org/browse/SR-2144
class ClientImp: NSObject, Client {
var server: Server?
var anotherServer: Server?
#if os(Linux)
init() {}
#else
override init() { super.init() }
#endif
class ClientImp: Client {
var server: Server!
var anotherServer: Server!
}
let serverContainer = DependencyContainer()
+1 -1
View File
@@ -290,7 +290,7 @@ class RuntimeArgumentsTests: XCTestCase {
// let name3 = "3"
// container.register { (port: Int, url: String!) in ServiceImp(name: name3, baseURL: url, port: port) as Service }
// let service3 = try! container.resolve(withArguments: 80, "http://example.com" as String!) as Service
// let service3 = try! container.resolve(arguments: 80, "http://example.com" as String!) as Service
// XCTAssertEqual(service3.name, name3)
}
+2 -2
View File
@@ -26,7 +26,7 @@ import XCTest
@testable import Dip
private protocol Server: class {
var client: Client? { get set }
var client: Client! { get set }
}
private protocol Client: class {
@@ -45,7 +45,7 @@ private func ==<T: ClientImp>(lhs: T, rhs: T) -> Bool {
}
private class ServerImp: Server, Hashable {
weak var client: Client?
weak var client: Client!
init() {}
var hashValue: Int {