Skip to content

Commit

Permalink
Merge pull request #8 from AliSoftware/release/0.2.0
Browse files Browse the repository at this point in the history
Release 0.2.0
  • Loading branch information
ilyapuchka authored Jul 4, 2016
2 parents e4faae6 + 94a0d55 commit 586102d
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 36 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ script:
- set -o pipefail && xcodebuild test -project DipUI/DipUI.xcodeproj -scheme DipUI-tvOS -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV 1080p,OS=latest' ONLY_ACTIVE_ARCH=NO | xcpretty -c
- pod lib lint --quick
- carthage build --no-skip-current

notifications:
email: false
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# CHANGELOG

## 0.2.0

* Multiple UI containers
[#7](https://github.com/AliSoftware/Dip/pull/7), [@ilyapuchka](https://github.com/ilyapuchka)

* dipTag can be `nil`
[#6](https://github.com/AliSoftware/Dip/pull/6), [@ilyapuchka](https://github.com/ilyapuchka)

## 0.1.0

* Fixed Dip version in podspec.
Expand Down
2 changes: 1 addition & 1 deletion Dip-UI.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Dip-UI"
s.version = "0.1.0"
s.version = "0.2.0"
s.summary = "Dip UI extension"

s.description = <<-DESC
Expand Down
4 changes: 2 additions & 2 deletions DipUI/DipUI.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.1.0;
CURRENT_PROJECT_VERSION = 0.2.0;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
Expand Down Expand Up @@ -612,7 +612,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.1.0;
CURRENT_PROJECT_VERSION = 0.2.0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
Expand Down
64 changes: 58 additions & 6 deletions DipUI/DipUITests/DipUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ import XCTest

#endif

class DipViewController: ViewController, StoryboardInstantiatable { }
class DipViewController: ViewController, StoryboardInstantiatable {}
class NilTagViewController: ViewController, StoryboardInstantiatable {}

class DipUITests: XCTestCase {

Expand Down Expand Up @@ -73,23 +74,74 @@ class DipUITests: XCTestCase {
XCTFail("Should not resolve when container is not set.")
}

DependencyContainer.uiContainer = container
DependencyContainer.uiContainers = [container]
storyboard.instantiateViewControllerWithIdentifier("ViewController")
}
func testThatItResolvesIfContainerAndTagAreSet() {

func testThatItResolvesIfContainerAndStringTagAreSet() {
var resolved = false
let container = DependencyContainer()
container.register(tag: "vc") { DipViewController() }
.resolveDependencies { _, _ in
resolved = true
}

DependencyContainer.uiContainer = container
DependencyContainer.uiContainers = [container]
storyboard.instantiateViewControllerWithIdentifier("DipViewController")
XCTAssertTrue(resolved, "Should resolve when container is set.")
XCTAssertTrue(resolved, "Should resolve when container and tag are set.")
}

func testThatItResolvesIfContainerAndNilTagAreSet() {
var resolved = false
let container = DependencyContainer()
container.register() { NilTagViewController() }
.resolveDependencies { _, _ 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(tag: "wrong tag") { DipViewController() }
.resolveDependencies { _, _ 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() { DipViewController() }
.resolveDependencies { _, _ 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(tag: "vc") { DipViewController() }
.resolveDependencies { container, _ in
XCTAssertTrue(container === container2)
resolved = true
}

DependencyContainer.uiContainers = [container1, container2]
storyboard.instantiateViewControllerWithIdentifier("DipViewController")
XCTAssertTrue(resolved, "Should resolve using second container")
}
}

protocol SomeService: class {
Expand Down
20 changes: 18 additions & 2 deletions DipUI/DipUITests/NSStoryboard.storyboard
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
</dependencies>
<scenes>
<!--Dip View Controller-->
Expand All @@ -20,6 +20,22 @@
</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="DipUI_OSXTests" customModuleProvider="target" 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>
Expand Down
27 changes: 25 additions & 2 deletions DipUI/DipUITests/UIStoryboard.storyboard
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="5AO-J3-7R4">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="5AO-J3-7R4">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--View Controller-->
Expand Down Expand Up @@ -48,5 +48,28 @@
</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="DipUI_iOSTests" customModuleProvider="target" 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" white="1" alpha="1" colorSpace="calibratedWhite"/>
</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>
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ To injecte dependencies in this view controller when it is instantiated from sto

1. Register the dependencies in the `DependencyContainer`, as well as `MyViewController`:

```swift
```swift
import Dip

@UIApplicationMain
Expand All @@ -71,17 +71,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
container.service = try container.resolve() as MyViewControllerService
}

DependencyContainer.uiContainer = container
DependencyContainer.uiContainers = [container]
}
}
```

> Note: All the depdencies are registered as implementations of abstractions (protocols). But `MyViewController` is registered as concrete type. But you can also make your view controller conform to some protocols and register them as implementations of these protocols.
In this case you can use `Nil` attribute type instead of `String`.

2. Set the container as one that will be used to inject dependencies in objects created by storyboards. You do it by setting static `uiContainer` property of `DependencyContainer ` class: `DependencyContainer.uiContainer = container`
2. Set the container as one that will be used to inject dependencies in objects created by storyboards. You do it by setting static `uiContainers` property of `DependencyContainer ` class: `DependencyContainer.uiContainers = [container]`

3. Make your view controller class conform to `StoryboardInstantiatable` protocol:

```swift
```swift
extension MyViewController: StoryboardInstantiatable { }
```

Expand All @@ -104,8 +106,8 @@ Now when view controller will be loaded from a storyboard Dip-UI will intercept
container.register { MyViewController() as MyScene }

extension MyViewController: StoryboardInstantiatable {
func didInstantiateFromStoryboard(container: DependencyContainer, tag: DependencyContainer.Tag) {
try! container.resolveDependenciesOf(self as MyScene, tag: tag)
func didInstantiateFromStoryboard(container: DependencyContainer, tag: DependencyContainer.Tag?) throws {
try container.resolveDependenciesOf(self as MyScene, tag: tag)
}
}
```
Expand Down
29 changes: 12 additions & 17 deletions Sources/StoryboardInstantiatable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,23 +118,18 @@ public protocol StoryboardInstantiatable {
```

*/
func didInstantiateFromStoryboard(container: DependencyContainer, tag: DependencyContainer.Tag)
func didInstantiateFromStoryboard(container: DependencyContainer, tag: DependencyContainer.Tag?) throws
}

extension StoryboardInstantiatable {
public func didInstantiateFromStoryboard(container: DependencyContainer, tag: DependencyContainer.Tag) {
do {
try container.resolveDependenciesOf(self, tag: tag)
}
catch {
print(error)
}
public func didInstantiateFromStoryboard(container: DependencyContainer, tag: DependencyContainer.Tag?) throws {
try container.resolveDependenciesOf(self, tag: tag)
}
}

extension DependencyContainer {
///A container that will be used to resolve dependencies of instances, created by stroyboards.
static public var uiContainer: DependencyContainer?
///Containers that will be used to resolve dependencies of instances, created by stroyboards.
static public var uiContainers: [DependencyContainer] = []
}

let DipTagAssociatedObjectKey = UnsafeMutablePointer<Int8>.alloc(1)
Expand All @@ -143,19 +138,19 @@ extension NSObject {

///A string tag that will be used to resolve dependencies of this instance
///if it implements `StoryboardInstantiatable` protocol.
@IBInspectable private(set) public var dipTag: String? {
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 }

if let
tag = newValue.map(DependencyContainer.Tag.String),
container = DependencyContainer.uiContainer,
instantiatable = self as? StoryboardInstantiatable {
instantiatable.didInstantiateFromStoryboard(container, tag: tag)
}
let tag = dipTag.map(DependencyContainer.Tag.String)

for container in DependencyContainer.uiContainers {
guard let _ = try? instantiatable.didInstantiateFromStoryboard(container, tag: tag) else { continue }
}
}
}

Expand Down

0 comments on commit 586102d

Please sign in to comment.