├── .swift-version
├── Cartfile
├── Cartfile.resolved
├── adding-dip-tag-in-ib.png
├── Package.swift
├── DipUI
├── DipUI.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── DipUI.xcscheme
│ └── project.pbxproj
├── DipUITests
│ ├── Info.plist
│ ├── NSStoryboard.storyboard
│ ├── TVStoryboard.storyboard
│ ├── UIStoryboard.storyboard
│ └── DipUITests.swift
└── DipUI
│ ├── Info.plist
│ └── DipUI.h
├── .gitignore
├── Dip-UI.podspec
├── LICENSE
├── .travis.yml
├── CHANGELOG.md
├── README.md
└── Sources
└── StoryboardInstantiatable.swift
/.swift-version:
--------------------------------------------------------------------------------
1 | 3.0
2 |
--------------------------------------------------------------------------------
/Cartfile:
--------------------------------------------------------------------------------
1 | github "AliSoftware/Dip" ~> 6.0
2 |
3 |
--------------------------------------------------------------------------------
/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "AliSoftware/Dip" "6.0"
2 |
--------------------------------------------------------------------------------
/adding-dip-tag-in-ib.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AliSoftware/Dip-UI/HEAD/adding-dip-tag-in-ib.png
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | import PackageDescription
2 |
3 | let package = Package(
4 | name: "DipUI",
5 | dependencies: [
6 | .Package(url: "https://github.com/AliSoftware/Dip.git", majorVersion: 6)
7 | ]
8 | )
9 |
--------------------------------------------------------------------------------
/DipUI/DipUI.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | build/
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata
15 | *.xccheckout
16 | *.xcscmblueprint
17 | profile
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 |
23 | # Bundler
24 | .bundle
25 |
26 | Carthage
27 | # We recommend against adding the Pods directory to your .gitignore. However
28 | # you should judge for yourself, the pros and cons are mentioned at:
29 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
30 | #
31 | # Note: if you ignore the Pods directory, make sure to uncomment
32 | # `pod install` in .travis.yml
33 | #
34 | # Pods/
35 |
36 | # SPM
37 | .build/
38 |
--------------------------------------------------------------------------------
/DipUI/DipUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/DipUI/DipUI/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Dip-UI.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "Dip-UI"
3 | s.version = "2.0"
4 | s.summary = "Dip UI extension"
5 |
6 | s.description = <<-DESC
7 | Dip-UI is a simple extension for Dip - Dependency Injection container for Swift.
8 | It adds features to support dependency injection for objects
9 | created by storyboards or loaded from nib files.
10 |
11 | DESC
12 |
13 | s.homepage = "https://github.com/AliSoftware/Dip-UI"
14 | s.license = 'MIT'
15 | s.authors = { "Ilya Puchka" => "ilya@puchka.me", "Olivier Halligon" => "olivier@halligon.net" }
16 | s.source = { :git => "https://github.com/AliSoftware/Dip-UI.git", :tag => s.version.to_s }
17 | s.social_media_url = 'https://twitter.com/aligatr'
18 |
19 | s.ios.deployment_target = '8.0'
20 | s.osx.deployment_target = '10.10'
21 | s.tvos.deployment_target = '9.0'
22 | s.watchos.deployment_target = '2.0'
23 |
24 | s.requires_arc = true
25 |
26 | s.source_files = 'Sources/**/*.swift'
27 |
28 | s.dependency 'Dip', '~> 6.0'
29 |
30 | end
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 Olivier Halligon , Ilya Puchka
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | osx_image: xcode8
3 |
4 | # cache: cocoapods
5 | # before_install:
6 | # - gem install cocoapods # Since Travis is not always on latest version
7 |
8 | install:
9 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet
10 | - gem install cocoapods --version 1.1.0.rc.2 --no-document
11 | - curl -OlL "https://github.com/Carthage/Carthage/releases/download/0.26.2/Carthage.pkg" && sudo installer -pkg "Carthage.pkg" -target / && rm "Carthage.pkg"
12 |
13 | script:
14 | - carthage bootstrap
15 | - set -o pipefail && xcodebuild -project DipUI/DipUI.xcodeproj -scheme DipUI -destination "platform=macOS" test | xcpretty
16 | - set -o pipefail && xcodebuild -project DipUI/DipUI.xcodeproj -scheme DipUI -destination "platform=iOS Simulator,name=iPhone 6S" test | xcpretty
17 | - set -o pipefail && xcodebuild -project DipUI/DipUI.xcodeproj -scheme DipUI -destination "platform=tvOS Simulator,name=Apple TV 1080p" test | xcpretty
18 | - set -o pipefail && xcodebuild -project DipUI/DipUI.xcodeproj -scheme DipUI -destination "platform=watchOS Simulator,name=Apple Watch - 38mm" build | xcpretty
19 | - pod repo update --silent && pod spec lint
20 | - carthage build --no-skip-current
21 |
22 | notifications:
23 | email: false
24 |
--------------------------------------------------------------------------------
/DipUI/DipUI/DipUI.h:
--------------------------------------------------------------------------------
1 | //
2 | // DipUI
3 | //
4 | // Copyright (c) 2016 Ilya Puchka
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import
26 | #import
27 |
28 | //! Project version number for DipUI.
29 | FOUNDATION_EXPORT double DipUIVersionNumber;
30 |
31 | //! Project version string for DipUI.
32 | FOUNDATION_EXPORT const unsigned char DipUIVersionString[];
33 |
34 | // In this header, you should import all the public headers of your framework using statements like #import
35 |
36 |
37 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # CHANGELOG
2 |
3 | ## 2.0.0
4 |
5 | * Swift 4 support
6 |
7 | ## 1.1
8 |
9 | * Dropped Swift 2.3 support.
10 | [#27](https://github.com/AliSoftware/Dip/issues/27), [@ilyapuchka](https://github.com/ilyapuchka)
11 |
12 | ## 1.0.2
13 |
14 | * Added Swift 2.3 compatibility. `swift2.3` brunch is no longer maintained.
15 | [#24](https://github.com/AliSoftware/Dip/issues/24), [@ilyapuchka](https://github.com/ilyapuchka)
16 |
17 | ## 1.0.1
18 |
19 | * Fixed Podspec
20 |
21 | ## 1.0.0
22 |
23 | * Swift 3 support
24 | [#14](https://github.com/AliSoftware/Dip/pull/14), [@ilyapuchka](https://github.com/ilyapuchka)
25 | * Added watchOS support
26 | [#12](https://github.com/AliSoftware/Dip/pull/12), [#13](https://github.com/AliSoftware/Dip/pull/13), [@ilyapuchka](https://github.com/ilyapuchka)
27 |
28 | ## 0.2.2
29 |
30 | * Fixed build warning when calling non-throwing `resolve` with `try`.
31 |
32 | ## 0.2.1
33 |
34 | * Fixed resolving instances using multiple UI containers.
35 |
36 | ## 0.2.0
37 |
38 | * Multiple UI containers
39 | [#7](https://github.com/AliSoftware/Dip/pull/7), [@ilyapuchka](https://github.com/ilyapuchka)
40 |
41 | * dipTag can be `nil`
42 | [#6](https://github.com/AliSoftware/Dip/pull/6), [@ilyapuchka](https://github.com/ilyapuchka)
43 |
44 | ## 0.1.0
45 |
46 | * Fixed Dip version in podspec.
47 |
48 | ## 0.0.2
49 |
50 | * Added Swift Package Manager support.
51 | [@ilyapuchka](https://github.com/ilyapuchka)
52 |
53 | ## 0.0.1
54 |
55 | #### Initial release
56 |
57 | * Implemented support for injecting dependencies into objects created by stoaryboards.
58 | [#1](https://github.com/AliSoftware/Dip/pull/1), [@ilyapuchka](https://github.com/ilyapuchka)
59 |
60 |
--------------------------------------------------------------------------------
/DipUI/DipUITests/NSStoryboard.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/DipUI/DipUI.xcodeproj/xcshareddata/xcschemes/DipUI.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
66 |
67 |
73 |
74 |
75 |
76 |
77 |
78 |
84 |
85 |
91 |
92 |
93 |
94 |
96 |
97 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/DipUI/DipUITests/TVStoryboard.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/DipUI/DipUITests/UIStoryboard.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](http://unmaintained.tech/)
2 | [](http://cocoapods.org/pods/Dip-UI)
3 | [](https://github.com/Carthage/Carthage)
4 | [](http://cocoapods.org/pods/Dip-UI)
5 | [](http://cocoapods.org/pods/Dip-UI)
6 | [](https://developer.apple.com/swift)
7 |
8 | __Dip-UI is a part of Dip since version 7.0.0. Thir repository will no longer be maintained.__
9 |
10 | # Dip-UI
11 |
12 | Dip-UI is an extension for [Dip](https://github.com/AliSoftware/Dip) that provides support for dependency injection using Dip in applications that utilize storyboards and nib files.
13 |
14 | ## Installation
15 |
16 | You can install Dip-UI using your favorite dependency manager:
17 |
18 | CocoaPods: `pod "Dip-UI"`
19 |
20 | > You need at least 1.1.0.rc.2 version of CocoaPods.
21 |
22 | Carthage: `github "AliSoftware/Dip-UI"`
23 |
24 | ## Usage
25 |
26 | Dip-UI provides a unified and simple pattern to resolve dependencies of view controllers (or any other `NSObject`'s) created by storyboards.
27 |
28 | Let's say you want to use Dip to inject dependencies in `MyViewController` class defined like this:
29 |
30 | ```swift
31 | class MyViewController: UIViewController {
32 | var logger: Logger?
33 | var tracker: Tracker?
34 | var router: Router?
35 | var presenter: MyViewControllerPresenter?
36 | var service: MyViewControllerService?
37 |
38 | /*...*/
39 | }
40 |
41 | ```
42 | > Note 1: Though constructor injection is a preferred way to inject dependencies, in this case we can not use it - we can not make storyboards to use custom constructor. We could do it using subclass of UI(NS)Storyboard and method-swizzling, but you don't expect such things in a Swift framework.
43 |
44 | > Note 2: Implicitly unwrapped optionals are used here to indicate that these dependencies are required for this class. You don't have to follow this pattern and are free to use plain optionals if you prefer.
45 |
46 | To inject dependencies in this view controller when it is instantiated from storyboard you need to follow next steps:
47 |
48 | - Register the dependencies in the `DependencyContainer`, as well as `MyViewController`:
49 |
50 | ```swift
51 | import DipUI
52 |
53 | @UIApplicationMain
54 | class AppDelegate: UIResponder, UIApplicationDelegate {
55 |
56 | let container = DependencyContainer { container in
57 | container.register(.singleton) { LoggerImp() as Logger }
58 | container.register(.singleton) { TrackerImp() as Tracker }
59 | container.register(.singleton) { RouterImp() as Router }
60 | container.register { MyViewControllerPresenterImp() as MyViewControllerPresenter }
61 | container.register { MyViewControllerServiceImp() as MyViewControllerService }
62 |
63 | container.register(storyboardType: MyViewController.self, tag: "myVC")
64 | .resolvingProperties { container, controller in
65 | controller.logger = try container.resolve() as Logger
66 | controller.tracker = try container.resolve() as Tracker
67 | controller.router = try container.resolve() as Router
68 | controller.presenter = try container.resolve() as MyViewControllerPresenter
69 | controller.service = try container.resolve() as MyViewControllerService
70 | }
71 |
72 | DependencyContainer.uiContainers = [container]
73 | }
74 | }
75 | ```
76 |
77 | > Note: All the depdencies are registered as implementations of abstractions (protocols). `MyViewController` is registered as concrete type. To register your view controller as a protocol read [here](#storyboardinstantiatable).
78 |
79 | - 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:
80 |
81 | ```swift
82 | DependencyContainer.uiContainers = [container]
83 | ```
84 |
85 | - Make your view controller class conform to `StoryboardInstantiatable` protocol:
86 |
87 | ```swift
88 | extension MyViewController: StoryboardInstantiatable { }
89 | ```
90 |
91 | > Tip: Do that in the Composition Root to avoid coupling your view controller's code with Dip.
92 |
93 | - In a storyboard (or in a nib file) set _Dip Tag_ attribute on your view controller. This value will be used to lookup definition for view controller, so it should be the same value that you used to register view controller in the container.
94 |
95 | 
96 |
97 | > Note: remember that `DependencyContainer` fallbacks to not-tagged definition if it does not find tagged definition, so you may register your view controller without tag, but you still need to set it in a storyboard. In this case you can use `Nil` attribute type instead of `String`.
98 |
99 | Now when view controller will be loaded from a storyboard Dip-UI will intercept the setter of `dipTag` property and will ask `DependencyContainer.uiContainer` to resolve its dependencies.
100 |
101 | ### StoryboardInstantiatable
102 |
103 | `StoryboardInstantiatable` protocol defines single method `didInstantiateFromStoryboard(_:tag:)` and provides its default implementation. In most cases you will not need to override it. But if you register your view controller as an impementation of some protocol instead of concrete type, or want to perform some pre/post actions, you will need to override it like this:
104 |
105 | ```swift
106 | container.register { MyViewController() as MyScene }
107 | extension MyViewController: StoryboardInstantiatable {
108 | func didInstantiateFromStoryboard(container: DependencyContainer, tag: DependencyContainer.Tag?) throws {
109 | try container.resolveDependenciesOf(self as MyScene, tag: tag)
110 | }
111 | }
112 | ```
113 |
114 |
115 | ## License
116 |
117 | **Dip-UI** is available under the **MIT license**. See the `LICENSE` file for more info.
118 |
--------------------------------------------------------------------------------
/DipUI/DipUITests/DipUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DipUI
3 | //
4 | // Copyright (c) 2016 Ilya Puchka
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import XCTest
26 | @testable import DipUI
27 |
28 | #if os(iOS) || os(tvOS)
29 | import UIKit
30 | typealias Storyboard = UIStoryboard
31 | typealias ViewController = UIViewController
32 | typealias StoryboardName = String
33 |
34 | extension UIStoryboard {
35 | @nonobjc
36 | @discardableResult func instantiateViewControllerWithIdentifier(_ identifier: String) -> UIViewController {
37 | return instantiateViewController(withIdentifier: identifier)
38 | }
39 | }
40 |
41 | #else
42 | import AppKit
43 | typealias Storyboard = NSStoryboard
44 | typealias ViewController = NSViewController
45 | typealias StoryboardName = NSStoryboard.Name
46 |
47 | extension NSStoryboard {
48 | @discardableResult func instantiateViewControllerWithIdentifier(_ identifier: String) -> NSViewController {
49 | return instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(identifier)) as! NSViewController
50 | }
51 | }
52 |
53 | #endif
54 |
55 | #if os(iOS)
56 | let storyboardName = "UIStoryboard"
57 | #elseif os(tvOS)
58 | let storyboardName = "TVStoryboard"
59 | #else
60 | let storyboardName = "NSStoryboard"
61 | #endif
62 |
63 | class DipViewController: ViewController, StoryboardInstantiatable {}
64 | class NilTagViewController: ViewController, StoryboardInstantiatable {}
65 |
66 | class DipUITests: XCTestCase {
67 |
68 | let storyboard: Storyboard = {
69 | let bundle = Bundle(for: DipUITests.self)
70 | return Storyboard(name: StoryboardName(storyboardName), bundle: bundle)
71 | }()
72 |
73 | func testThatViewControllerHasDipTagProperty() {
74 | let viewController = storyboard.instantiateViewControllerWithIdentifier("DipViewController")
75 | XCTAssertEqual(viewController.dipTag, "vc")
76 | }
77 |
78 | func testThatItDoesNotResolveIfContainerIsNotSet() {
79 | let container = DependencyContainer()
80 | container.register(tag: "vc") { ViewController() }
81 | .resolvingProperties { _, _ in
82 | XCTFail("Should not resolve when container is not set.")
83 | }
84 |
85 | storyboard.instantiateViewControllerWithIdentifier("DipViewController")
86 | }
87 |
88 | func testThatItDoesNotResolveIfTagIsNotSet() {
89 | let container = DependencyContainer()
90 | container.register(tag: "vc") { ViewController() }
91 | .resolvingProperties { _, _ in
92 | XCTFail("Should not resolve when container is not set.")
93 | }
94 |
95 | DependencyContainer.uiContainers = [container]
96 | storyboard.instantiateViewControllerWithIdentifier("ViewController")
97 | }
98 |
99 | func testThatItResolvesIfContainerAndStringTagAreSet() {
100 | var resolved = false
101 | let container = DependencyContainer()
102 | container.register(storyboardType: DipViewController.self, tag: "vc")
103 | .resolvingProperties { _, _ in
104 | resolved = true
105 | }
106 |
107 | DependencyContainer.uiContainers = [container]
108 | storyboard.instantiateViewControllerWithIdentifier("DipViewController")
109 | XCTAssertTrue(resolved, "Should resolve when container and tag are set.")
110 | }
111 |
112 | func testThatItResolvesIfContainerAndNilTagAreSet() {
113 | var resolved = false
114 | let container = DependencyContainer()
115 | container.register(storyboardType: NilTagViewController.self)
116 | .resolvingProperties { _, _ in
117 | resolved = true
118 | }
119 |
120 | DependencyContainer.uiContainers = [container]
121 | storyboard.instantiateViewControllerWithIdentifier("NilTagViewController")
122 | XCTAssertTrue(resolved, "Should resolve when container and nil tag are set.")
123 | }
124 |
125 | func testThatItDoesNotResolveIfTagDoesNotMatch() {
126 | let container = DependencyContainer()
127 | container.register(storyboardType: DipViewController.self, tag: "wrong tag")
128 | .resolvingProperties { _, _ in
129 | XCTFail("Should not resolve when container is not set.")
130 | }
131 |
132 | DependencyContainer.uiContainers = [container]
133 | storyboard.instantiateViewControllerWithIdentifier("DipViewController")
134 | }
135 |
136 | func testThatItResolvesWithDefinitionWithNoTag() {
137 | var resolved = false
138 | let container = DependencyContainer()
139 | container.register(storyboardType: DipViewController.self)
140 | .resolvingProperties { _, _ in
141 | resolved = true
142 | }
143 |
144 | DependencyContainer.uiContainers = [container]
145 | storyboard.instantiateViewControllerWithIdentifier("DipViewController")
146 | XCTAssertTrue(resolved, "Should fallback to definition with no tag.")
147 | }
148 |
149 | func testThatItIteratesUIContainers() {
150 | var resolved = false
151 | let container1 = DependencyContainer()
152 | let container2 = DependencyContainer()
153 | container2.register(storyboardType: DipViewController.self, tag: "vc")
154 | .resolvingProperties { container, _ in
155 | XCTAssertTrue(container === container2)
156 | resolved = true
157 | }
158 |
159 | DependencyContainer.uiContainers = [container1, container2]
160 | storyboard.instantiateViewControllerWithIdentifier("DipViewController")
161 | XCTAssertTrue(resolved, "Should resolve using second container")
162 | }
163 | }
164 |
165 | protocol SomeService: class {
166 | weak var delegate: SomeServiceDelegate? { get set }
167 | }
168 | protocol SomeServiceDelegate: class { }
169 | class SomeServiceImp: SomeService {
170 | weak var delegate: SomeServiceDelegate?
171 | init(delegate: SomeServiceDelegate) {
172 | self.delegate = delegate
173 | }
174 | init(){}
175 | }
176 |
177 | protocol OtherService: class {
178 | weak var delegate: OtherServiceDelegate? { get set }
179 | }
180 | protocol OtherServiceDelegate: class {}
181 | class OtherServiceImp: OtherService {
182 | weak var delegate: OtherServiceDelegate?
183 | init(delegate: OtherServiceDelegate){
184 | self.delegate = delegate
185 | }
186 | init(){}
187 | }
188 |
189 |
190 | protocol SomeScreen: class {
191 | var someService: SomeService? { get set }
192 | var otherService: OtherService? { get set }
193 | }
194 |
195 | class ViewControllerImp: SomeScreen, SomeServiceDelegate, OtherServiceDelegate {
196 | var someService: SomeService?
197 | var otherService: OtherService?
198 | init(){}
199 | }
200 |
201 | extension DipUITests {
202 |
203 | func testThatItDoesNotCreateNewInstanceWhenResolvingDependenciesOfExternalInstance() {
204 | let container = DependencyContainer()
205 |
206 | //given
207 | var factoryCalled = false
208 | container.register(.shared) { () -> SomeScreen in
209 | factoryCalled = true
210 | return ViewControllerImp() as SomeScreen
211 | }
212 |
213 | //when
214 | let screen = ViewControllerImp()
215 | try! container.resolveDependencies(of: screen as SomeScreen)
216 |
217 | //then
218 | XCTAssertFalse(factoryCalled, "Container should not create new instance when resolving dependencies of external instance.")
219 | }
220 |
221 | func testThatItResolvesInstanceThatImplementsSeveralProtocols() {
222 | let container = DependencyContainer()
223 |
224 | //given
225 | container.register(.shared) { ViewControllerImp() as SomeScreen }
226 | .resolvingProperties { container, resolved in
227 |
228 | //manually provide resolved instance for the delegate properties
229 | resolved.someService = try container.resolve() as SomeService
230 | resolved.someService?.delegate = resolved as? SomeServiceDelegate
231 | resolved.otherService = try container.resolve(arguments: resolved as! OtherServiceDelegate) as OtherService
232 | }
233 |
234 | container.register(.shared) { SomeServiceImp() as SomeService }
235 | container.register(.shared) { OtherServiceImp(delegate: $0) as OtherService }
236 |
237 | //when
238 | let screen = try! container.resolve() as SomeScreen
239 |
240 | //then
241 | XCTAssertNotNil(screen.someService)
242 | XCTAssertNotNil(screen.otherService)
243 |
244 | XCTAssertTrue(screen.someService?.delegate === screen)
245 | XCTAssertTrue(screen.otherService?.delegate === screen)
246 | }
247 |
248 | }
249 |
--------------------------------------------------------------------------------
/Sources/StoryboardInstantiatable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DipUI
3 | //
4 | // Copyright (c) 2016 Ilya Puchka
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Dip
26 |
27 | extension DependencyContainer {
28 | ///Containers that will be used to resolve dependencies of instances, created by stroyboards.
29 | static public var uiContainers: [DependencyContainer] = {
30 | #if os(watchOS)
31 | swizzleAwakeWithContext
32 | #endif
33 | return []
34 | }()
35 |
36 | /**
37 | Resolves dependencies of passed in instance.
38 | Use this method to resolve dependencies of object created by storyboard.
39 | The type of the instance should be registered in the container.
40 |
41 | You should call this method only from implementation of `didInstantiateFromStoryboard(_:tag:)`
42 | of `StoryboardInstantiatable` protocol if you override its default implementation.
43 |
44 | This method will do the same as `resolve(tag:) as T`, but instead of creating
45 | a new intance with a registered factory it will use passed in instance as a resolved instance.
46 |
47 | - parameters:
48 | - instance: The object which dependencies should be resolved
49 | - tag: An optional tag used to register the type (`T`) in the container
50 |
51 | **Example**:
52 |
53 | ```swift
54 | class ViewController: UIViewController, ServiceDelegate, StoryboardInstantiatable {
55 | var service: Service?
56 |
57 | func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag?) throws {
58 | try container.resolveDependencies(of: self as ServiceDelegate, tag: "vc")
59 | }
60 | }
61 |
62 | class ServiceImp: Service {
63 | weak var delegate: ServiceDelegate?
64 | }
65 |
66 | container.register(tag: "vc") { ViewController() }
67 | .resolvingProperties { container, controller in
68 | controller.service = try container.resolve() as Service
69 | controller.service.delegate = controller
70 | }
71 |
72 | container.register { ServiceImp() as Service }
73 | ```
74 |
75 | - seealso: `register(_:type:tag:factory:)`, `didInstantiateFromStoryboard(_:tag:)`
76 |
77 | */
78 | public func resolveDependencies(of instance: T, tag: Tag? = nil) throws {
79 | _ = try resolve(tag: tag) { (_: () throws -> T) in instance }
80 | }
81 |
82 | /**
83 | Register storyboard type `T` which has to conform to `StoryboardInstantiatable` and associate it with an optional tag.
84 |
85 | - parameters:
86 | - type: Storyboard type to register definition for.
87 | - tag: The arbitrary tag to associate this factory with. Pass `nil` to associate with any tag. Default value is `nil`.
88 |
89 | - returns: A registered definition.
90 |
91 | - note: This method will register concrete types. If you need to register
92 | as abstract types you should use standard `register` method from Dip.
93 | You should cast the factory return type to the protocol you want to
94 | register it for (unless you want to register concrete type) or
95 | provide `type` parameter.
96 |
97 | - seealso: `Definition`, `ComponentScope`, `DependencyTagConvertible`
98 |
99 | **Example**:
100 | ```swift
101 | // Register MyViewController
102 | container.register(storyboardType: MyViewController.self)
103 | // or
104 | container.register(tag: "myVC") { MyViewController() as MyViewControllerType }
105 | ```
106 | */
107 | public func register(storyboardType type: T.Type, tag: DependencyTagConvertible? = nil) -> Dip.Definition where T: StoryboardInstantiatable {
108 | return register(.unique, type: type, tag: tag, factory: { T() })
109 | }
110 |
111 | }
112 |
113 | #if os(watchOS)
114 | public protocol StoryboardInstantiatableType {}
115 | #else
116 | public typealias StoryboardInstantiatableType = NSObjectProtocol
117 | #endif
118 |
119 | public protocol StoryboardInstantiatable: StoryboardInstantiatableType {
120 |
121 | /**
122 | This method will be called if you set a `dipTag` attirbute on the object in a storyboard
123 | that conforms to `StoryboardInstantiatable` protocol.
124 |
125 | - parameters:
126 | - tag: The tag value, that was set on the object in a storyboard
127 | - container: The `DependencyContainer` associated with storyboards
128 |
129 | The type that implements `StoryboardInstantiatable` protocol should be registered in `UIStoryboard.container`.
130 | Default implementation of that method calls `resolveDependenciesOf(_:tag:)`
131 | and pass it `self` instance and the tag.
132 |
133 | Usually you will not need to override the default implementation of this method
134 | if you registered the type of the instance as a concrete type in the container.
135 | Then you only need to add conformance to `StoryboardInstantiatable`.
136 |
137 | You may want to override it if you want to add custom logic before/after resolving dependencies
138 | or you want to resolve the instance as implementation of some protocol which it conforms to.
139 |
140 | - warning: This method will be called after `init?(coder:)` but before `awakeFromNib` method of `NSObject`.
141 | On watchOS this method will be called before `awakeWithContext(_:)`.
142 |
143 | **Example**:
144 |
145 | ```swift
146 | extension MyViewController: SomeProtocol { ... }
147 |
148 | extension MyViewController: StoryboardInstantiatable {
149 | func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag) throws {
150 | //resolve dependencies of the instance as SomeProtocol type
151 | try container.resolveDependencies(of: self as SomeProtocol, tag: tag)
152 | //do some additional setup here
153 | }
154 | }
155 | ```
156 | */
157 | func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag?) throws
158 |
159 | }
160 |
161 | extension StoryboardInstantiatable {
162 | public func didInstantiateFromStoryboard(_ container: DependencyContainer, tag: DependencyContainer.Tag?) throws {
163 | try container.resolveDependencies(of: self, tag: tag)
164 | }
165 | }
166 |
167 | #if os(iOS) || os(tvOS) || os(OSX)
168 |
169 | #if os(iOS) || os(tvOS)
170 | import UIKit
171 | #elseif os(OSX)
172 | import AppKit
173 | #endif
174 |
175 | let DipTagAssociatedObjectKey = UnsafeMutablePointer.allocate(capacity: 1)
176 |
177 | extension NSObject {
178 |
179 | ///A string tag that will be used to resolve dependencies of this instance
180 | ///if it implements `StoryboardInstantiatable` protocol.
181 | @objc private(set) public var dipTag: String? {
182 | get {
183 | return objc_getAssociatedObject(self, DipTagAssociatedObjectKey) as? String
184 | }
185 | set {
186 | objc_setAssociatedObject(self, DipTagAssociatedObjectKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
187 | guard let instantiatable = self as? StoryboardInstantiatable else { return }
188 |
189 | let tag = dipTag.map(DependencyContainer.Tag.String)
190 |
191 | for (index, container) in DependencyContainer.uiContainers.enumerated() {
192 | do {
193 | log("Trying to resolve \(type(of: self)) with UI container at index \(index)")
194 | try instantiatable.didInstantiateFromStoryboard(container, tag: tag)
195 | log("Resolved \(type(of: self))")
196 | return
197 | } catch { }
198 | }
199 | }
200 | }
201 |
202 | }
203 |
204 | func log(_ message: Any) {
205 | if Dip.LogLevel.Errors.rawValue <= Dip.logLevel.rawValue {
206 | Dip.logger(logLevel, message)
207 | }
208 | }
209 |
210 | #else
211 | import WatchKit
212 |
213 | let swizzleAwakeWithContext: Void = {
214 | let originalSelector = #selector(WKInterfaceController.awake(withContext:))
215 | let swizzledSelector = #selector(WKInterfaceController.dip_awake(withContext:))
216 |
217 | guard let originalMethod = class_getInstanceMethod(WKInterfaceController.self, originalSelector),
218 | let swizzledMethod = class_getInstanceMethod(WKInterfaceController.self, swizzledSelector) else { return }
219 |
220 | let didAddMethod = class_addMethod(WKInterfaceController.self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
221 |
222 | if didAddMethod {
223 | class_replaceMethod(WKInterfaceController.self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
224 | } else {
225 | method_exchangeImplementations(originalMethod, swizzledMethod)
226 | }
227 | }()
228 |
229 | extension WKInterfaceController: StoryboardInstantiatableType {
230 |
231 | @objc func dip_awake(withContext context: AnyObject?) {
232 | defer { self.dip_awake(withContext: context) }
233 | guard let instantiatable = self as? StoryboardInstantiatable else { return }
234 |
235 | for container in DependencyContainer.uiContainers {
236 | guard let _ = try? instantiatable.didInstantiateFromStoryboard(container, tag: nil) else { continue }
237 | break
238 | }
239 | }
240 |
241 | }
242 |
243 | #endif
244 |
--------------------------------------------------------------------------------
/DipUI/DipUI.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 09B0361E1C5E8029001EA5B7 /* DipUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B0361D1C5E8029001EA5B7 /* DipUITests.swift */; };
11 | 09B036711C5E864C001EA5B7 /* DipUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 09B036111C5E8028001EA5B7 /* DipUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
12 | 09B036771C5E86BE001EA5B7 /* StoryboardInstantiatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B036281C5E812D001EA5B7 /* StoryboardInstantiatable.swift */; };
13 | 09D387641D8E97E600483D0D /* DipUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09B0365A1C5E836B001EA5B7 /* DipUI.framework */; };
14 | /* End PBXBuildFile section */
15 |
16 | /* Begin PBXFileReference section */
17 | 092624801C5E8ACD00A31D1A /* UIStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UIStoryboard.storyboard; sourceTree = ""; };
18 | 092624831C5E8AFE00A31D1A /* NSStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NSStoryboard.storyboard; sourceTree = ""; };
19 | 092BACA31D63AFA50017CE47 /* TVStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = TVStoryboard.storyboard; sourceTree = ""; };
20 | 0969D1B91C60099600A2142B /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = CHANGELOG.md; path = ../CHANGELOG.md; sourceTree = ""; };
21 | 0969D1BA1C60099600A2142B /* Dip-UI.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; name = "Dip-UI.podspec"; path = "../Dip-UI.podspec"; sourceTree = ""; };
22 | 0969D1BB1C60099600A2142B /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; };
23 | 0969D1BC1C60099600A2142B /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; };
24 | 09B036111C5E8028001EA5B7 /* DipUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DipUI.h; sourceTree = ""; };
25 | 09B036131C5E8028001EA5B7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
26 | 09B036181C5E8029001EA5B7 /* DipUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DipUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
27 | 09B0361D1C5E8029001EA5B7 /* DipUITests.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = DipUITests.swift; sourceTree = ""; tabWidth = 2; };
28 | 09B0361F1C5E8029001EA5B7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
29 | 09B036281C5E812D001EA5B7 /* StoryboardInstantiatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StoryboardInstantiatable.swift; path = ../../Sources/StoryboardInstantiatable.swift; sourceTree = ""; };
30 | 09B0365A1C5E836B001EA5B7 /* DipUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DipUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
31 | /* End PBXFileReference section */
32 |
33 | /* Begin PBXFrameworksBuildPhase section */
34 | 09B036151C5E8029001EA5B7 /* Frameworks */ = {
35 | isa = PBXFrameworksBuildPhase;
36 | buildActionMask = 2147483647;
37 | files = (
38 | 09D387641D8E97E600483D0D /* DipUI.framework in Frameworks */,
39 | );
40 | runOnlyForDeploymentPostprocessing = 0;
41 | };
42 | 09B036561C5E836B001EA5B7 /* Frameworks */ = {
43 | isa = PBXFrameworksBuildPhase;
44 | buildActionMask = 2147483647;
45 | files = (
46 | );
47 | runOnlyForDeploymentPostprocessing = 0;
48 | };
49 | /* End PBXFrameworksBuildPhase section */
50 |
51 | /* Begin PBXGroup section */
52 | 0969D1B81C60098400A2142B /* Podspec Metadata */ = {
53 | isa = PBXGroup;
54 | children = (
55 | 0969D1B91C60099600A2142B /* CHANGELOG.md */,
56 | 0969D1BA1C60099600A2142B /* Dip-UI.podspec */,
57 | 0969D1BB1C60099600A2142B /* LICENSE */,
58 | 0969D1BC1C60099600A2142B /* README.md */,
59 | );
60 | name = "Podspec Metadata";
61 | sourceTree = "";
62 | };
63 | 09B036041C5E8028001EA5B7 = {
64 | isa = PBXGroup;
65 | children = (
66 | 09B036101C5E8028001EA5B7 /* DipUI */,
67 | 09B0361C1C5E8029001EA5B7 /* DipUITests */,
68 | 09B0360F1C5E8028001EA5B7 /* Products */,
69 | 0969D1B81C60098400A2142B /* Podspec Metadata */,
70 | );
71 | indentWidth = 2;
72 | sourceTree = "";
73 | tabWidth = 2;
74 | };
75 | 09B0360F1C5E8028001EA5B7 /* Products */ = {
76 | isa = PBXGroup;
77 | children = (
78 | 09B036181C5E8029001EA5B7 /* DipUITests.xctest */,
79 | 09B0365A1C5E836B001EA5B7 /* DipUI.framework */,
80 | );
81 | name = Products;
82 | sourceTree = "";
83 | };
84 | 09B036101C5E8028001EA5B7 /* DipUI */ = {
85 | isa = PBXGroup;
86 | children = (
87 | 09B036111C5E8028001EA5B7 /* DipUI.h */,
88 | 09B036281C5E812D001EA5B7 /* StoryboardInstantiatable.swift */,
89 | 09B036131C5E8028001EA5B7 /* Info.plist */,
90 | );
91 | path = DipUI;
92 | sourceTree = "";
93 | };
94 | 09B0361C1C5E8029001EA5B7 /* DipUITests */ = {
95 | isa = PBXGroup;
96 | children = (
97 | 09B0361D1C5E8029001EA5B7 /* DipUITests.swift */,
98 | 092624801C5E8ACD00A31D1A /* UIStoryboard.storyboard */,
99 | 092BACA31D63AFA50017CE47 /* TVStoryboard.storyboard */,
100 | 092624831C5E8AFE00A31D1A /* NSStoryboard.storyboard */,
101 | 09B0361F1C5E8029001EA5B7 /* Info.plist */,
102 | );
103 | path = DipUITests;
104 | sourceTree = "";
105 | };
106 | /* End PBXGroup section */
107 |
108 | /* Begin PBXHeadersBuildPhase section */
109 | 09B036571C5E836B001EA5B7 /* Headers */ = {
110 | isa = PBXHeadersBuildPhase;
111 | buildActionMask = 2147483647;
112 | files = (
113 | 09B036711C5E864C001EA5B7 /* DipUI.h in Headers */,
114 | );
115 | runOnlyForDeploymentPostprocessing = 0;
116 | };
117 | /* End PBXHeadersBuildPhase section */
118 |
119 | /* Begin PBXNativeTarget section */
120 | 09B036171C5E8029001EA5B7 /* DipUITests */ = {
121 | isa = PBXNativeTarget;
122 | buildConfigurationList = 09B036251C5E8029001EA5B7 /* Build configuration list for PBXNativeTarget "DipUITests" */;
123 | buildPhases = (
124 | 09B036141C5E8029001EA5B7 /* Sources */,
125 | 09B036151C5E8029001EA5B7 /* Frameworks */,
126 | 0966BAEF1D651EB7009C6CC3 /* ShellScript */,
127 | 09B036161C5E8029001EA5B7 /* Resources */,
128 | 0966BAF01D652F19009C6CC3 /* ShellScript */,
129 | );
130 | buildRules = (
131 | );
132 | dependencies = (
133 | );
134 | name = DipUITests;
135 | productName = DipUITests;
136 | productReference = 09B036181C5E8029001EA5B7 /* DipUITests.xctest */;
137 | productType = "com.apple.product-type.bundle.unit-test";
138 | };
139 | 09B036591C5E836B001EA5B7 /* DipUI */ = {
140 | isa = PBXNativeTarget;
141 | buildConfigurationList = 09B0366B1C5E836B001EA5B7 /* Build configuration list for PBXNativeTarget "DipUI" */;
142 | buildPhases = (
143 | 09B036551C5E836B001EA5B7 /* Sources */,
144 | 09B036561C5E836B001EA5B7 /* Frameworks */,
145 | 09B036571C5E836B001EA5B7 /* Headers */,
146 | 09B036581C5E836B001EA5B7 /* Resources */,
147 | );
148 | buildRules = (
149 | );
150 | dependencies = (
151 | );
152 | name = DipUI;
153 | productName = "DipUI-OSX";
154 | productReference = 09B0365A1C5E836B001EA5B7 /* DipUI.framework */;
155 | productType = "com.apple.product-type.framework";
156 | };
157 | /* End PBXNativeTarget section */
158 |
159 | /* Begin PBXProject section */
160 | 09B036051C5E8028001EA5B7 /* Project object */ = {
161 | isa = PBXProject;
162 | attributes = {
163 | LastSwiftUpdateCheck = 0720;
164 | LastUpgradeCheck = 0900;
165 | ORGANIZATIONNAME = "";
166 | TargetAttributes = {
167 | 09B036171C5E8029001EA5B7 = {
168 | CreatedOnToolsVersion = 7.2;
169 | DevelopmentTeam = 87BXKFRW6K;
170 | };
171 | 09B036591C5E836B001EA5B7 = {
172 | CreatedOnToolsVersion = 7.2;
173 | };
174 | };
175 | };
176 | buildConfigurationList = 09B036081C5E8028001EA5B7 /* Build configuration list for PBXProject "DipUI" */;
177 | compatibilityVersion = "Xcode 3.2";
178 | developmentRegion = English;
179 | hasScannedForEncodings = 0;
180 | knownRegions = (
181 | en,
182 | );
183 | mainGroup = 09B036041C5E8028001EA5B7;
184 | productRefGroup = 09B0360F1C5E8028001EA5B7 /* Products */;
185 | projectDirPath = "";
186 | projectRoot = "";
187 | targets = (
188 | 09B036591C5E836B001EA5B7 /* DipUI */,
189 | 09B036171C5E8029001EA5B7 /* DipUITests */,
190 | );
191 | };
192 | /* End PBXProject section */
193 |
194 | /* Begin PBXResourcesBuildPhase section */
195 | 09B036161C5E8029001EA5B7 /* Resources */ = {
196 | isa = PBXResourcesBuildPhase;
197 | buildActionMask = 2147483647;
198 | files = (
199 | );
200 | runOnlyForDeploymentPostprocessing = 0;
201 | };
202 | 09B036581C5E836B001EA5B7 /* Resources */ = {
203 | isa = PBXResourcesBuildPhase;
204 | buildActionMask = 2147483647;
205 | files = (
206 | );
207 | runOnlyForDeploymentPostprocessing = 0;
208 | };
209 | /* End PBXResourcesBuildPhase section */
210 |
211 | /* Begin PBXShellScriptBuildPhase section */
212 | 0966BAEF1D651EB7009C6CC3 /* ShellScript */ = {
213 | isa = PBXShellScriptBuildPhase;
214 | buildActionMask = 2147483647;
215 | files = (
216 | );
217 | inputPaths = (
218 | );
219 | outputPaths = (
220 | );
221 | runOnlyForDeploymentPostprocessing = 0;
222 | shellPath = /bin/sh;
223 | shellScript = "ibtool --compilation-directory \"${TARGET_TEMP_DIR}\" \"${SRCROOT}/DipUITests/${STORYBOARD_NAME_PREFIX}Storyboard.storyboard\"\nibtool --link \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\" \"${TARGET_TEMP_DIR}/${STORYBOARD_NAME_PREFIX}Storyboard.storyboardc\"\n";
224 | };
225 | 0966BAF01D652F19009C6CC3 /* ShellScript */ = {
226 | isa = PBXShellScriptBuildPhase;
227 | buildActionMask = 2147483647;
228 | files = (
229 | );
230 | inputPaths = (
231 | );
232 | outputPaths = (
233 | );
234 | runOnlyForDeploymentPostprocessing = 0;
235 | shellPath = /bin/sh;
236 | shellScript = "for path in $FRAMEWORK_SEARCH_PATHS\ndo\n if [ -d \"${path}/Dip.framework\" ] && [[ $path == *\"Carthage\"* ]]; then\n export SCRIPT_INPUT_FILE_COUNT=1\n export SCRIPT_INPUT_FILE_0=\"${path}/Dip.framework\"\n /usr/local/bin/carthage copy-frameworks\n break\n fi\ndone\n\n";
237 | };
238 | /* End PBXShellScriptBuildPhase section */
239 |
240 | /* Begin PBXSourcesBuildPhase section */
241 | 09B036141C5E8029001EA5B7 /* Sources */ = {
242 | isa = PBXSourcesBuildPhase;
243 | buildActionMask = 2147483647;
244 | files = (
245 | 09B0361E1C5E8029001EA5B7 /* DipUITests.swift in Sources */,
246 | );
247 | runOnlyForDeploymentPostprocessing = 0;
248 | };
249 | 09B036551C5E836B001EA5B7 /* Sources */ = {
250 | isa = PBXSourcesBuildPhase;
251 | buildActionMask = 2147483647;
252 | files = (
253 | 09B036771C5E86BE001EA5B7 /* StoryboardInstantiatable.swift in Sources */,
254 | );
255 | runOnlyForDeploymentPostprocessing = 0;
256 | };
257 | /* End PBXSourcesBuildPhase section */
258 |
259 | /* Begin XCBuildConfiguration section */
260 | 09B036201C5E8029001EA5B7 /* Debug */ = {
261 | isa = XCBuildConfiguration;
262 | buildSettings = {
263 | ALWAYS_SEARCH_USER_PATHS = NO;
264 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
265 | CLANG_CXX_LIBRARY = "libc++";
266 | CLANG_ENABLE_MODULES = YES;
267 | CLANG_ENABLE_OBJC_ARC = YES;
268 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
269 | CLANG_WARN_BOOL_CONVERSION = YES;
270 | CLANG_WARN_COMMA = YES;
271 | CLANG_WARN_CONSTANT_CONVERSION = YES;
272 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
273 | CLANG_WARN_EMPTY_BODY = YES;
274 | CLANG_WARN_ENUM_CONVERSION = YES;
275 | CLANG_WARN_INFINITE_RECURSION = YES;
276 | CLANG_WARN_INT_CONVERSION = YES;
277 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
278 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
279 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
280 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
281 | CLANG_WARN_STRICT_PROTOTYPES = YES;
282 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
283 | CLANG_WARN_UNREACHABLE_CODE = YES;
284 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
285 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
286 | COPY_PHASE_STRIP = NO;
287 | CURRENT_PROJECT_VERSION = 2.0.0;
288 | DEBUG_INFORMATION_FORMAT = dwarf;
289 | ENABLE_STRICT_OBJC_MSGSEND = YES;
290 | ENABLE_TESTABILITY = YES;
291 | FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../Carthage/Build/Mac";
292 | "FRAMEWORK_SEARCH_PATHS[sdk=appletvos*]" = "$(SRCROOT)/../Carthage/Build/tvOS";
293 | "FRAMEWORK_SEARCH_PATHS[sdk=appletvsimulator*]" = "$(SRCROOT)/../Carthage/Build/tvOS";
294 | "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = "$(SRCROOT)/../Carthage/Build/iOS";
295 | "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = "$(SRCROOT)/../Carthage/Build/iOS";
296 | "FRAMEWORK_SEARCH_PATHS[sdk=macosx*]" = "$(SRCROOT)/../Carthage/Build/Mac";
297 | "FRAMEWORK_SEARCH_PATHS[sdk=watchos*]" = "$(SRCROOT)/../Carthage/Build/watchOS";
298 | "FRAMEWORK_SEARCH_PATHS[sdk=watchsimulator*]" = "$(SRCROOT)/../Carthage/Build/watchOS";
299 | GCC_C_LANGUAGE_STANDARD = gnu99;
300 | GCC_DYNAMIC_NO_PIC = NO;
301 | GCC_NO_COMMON_BLOCKS = YES;
302 | GCC_OPTIMIZATION_LEVEL = 0;
303 | GCC_PREPROCESSOR_DEFINITIONS = (
304 | "DEBUG=1",
305 | "$(inherited)",
306 | );
307 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
308 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
309 | GCC_WARN_UNDECLARED_SELECTOR = YES;
310 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
311 | GCC_WARN_UNUSED_FUNCTION = YES;
312 | GCC_WARN_UNUSED_VARIABLE = YES;
313 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
314 | MACOSX_DEPLOYMENT_TARGET = 10.10;
315 | MTL_ENABLE_DEBUG_INFO = YES;
316 | ONLY_ACTIVE_ARCH = YES;
317 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator";
318 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
319 | SWIFT_VERSION = 4.0;
320 | TARGETED_DEVICE_FAMILY = "1,2,3,4";
321 | TVOS_DEPLOYMENT_TARGET = 9.0;
322 | VERSIONING_SYSTEM = "apple-generic";
323 | VERSION_INFO_PREFIX = "";
324 | WATCHOS_DEPLOYMENT_TARGET = 2.2;
325 | };
326 | name = Debug;
327 | };
328 | 09B036211C5E8029001EA5B7 /* Release */ = {
329 | isa = XCBuildConfiguration;
330 | buildSettings = {
331 | ALWAYS_SEARCH_USER_PATHS = NO;
332 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
333 | CLANG_CXX_LIBRARY = "libc++";
334 | CLANG_ENABLE_MODULES = YES;
335 | CLANG_ENABLE_OBJC_ARC = YES;
336 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
337 | CLANG_WARN_BOOL_CONVERSION = YES;
338 | CLANG_WARN_COMMA = YES;
339 | CLANG_WARN_CONSTANT_CONVERSION = YES;
340 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
341 | CLANG_WARN_EMPTY_BODY = YES;
342 | CLANG_WARN_ENUM_CONVERSION = YES;
343 | CLANG_WARN_INFINITE_RECURSION = YES;
344 | CLANG_WARN_INT_CONVERSION = YES;
345 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
346 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
347 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
348 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
349 | CLANG_WARN_STRICT_PROTOTYPES = YES;
350 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
351 | CLANG_WARN_UNREACHABLE_CODE = YES;
352 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
353 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
354 | COPY_PHASE_STRIP = NO;
355 | CURRENT_PROJECT_VERSION = 2.0.0;
356 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
357 | ENABLE_NS_ASSERTIONS = NO;
358 | ENABLE_STRICT_OBJC_MSGSEND = YES;
359 | FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../Carthage/Build/Mac";
360 | "FRAMEWORK_SEARCH_PATHS[sdk=appletvos*]" = "$(SRCROOT)/../Carthage/Build/tvOS";
361 | "FRAMEWORK_SEARCH_PATHS[sdk=appletvsimulator*]" = "$(SRCROOT)/../Carthage/Build/tvOS";
362 | "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = "$(SRCROOT)/../Carthage/Build/iOS";
363 | "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = "$(SRCROOT)/../Carthage/Build/iOS";
364 | "FRAMEWORK_SEARCH_PATHS[sdk=macosx*]" = "$(SRCROOT)/../Carthage/Build/Mac";
365 | "FRAMEWORK_SEARCH_PATHS[sdk=watchos*]" = "$(SRCROOT)/../Carthage/Build/watchOS";
366 | "FRAMEWORK_SEARCH_PATHS[sdk=watchsimulator*]" = "$(SRCROOT)/../Carthage/Build/watchOS";
367 | GCC_C_LANGUAGE_STANDARD = gnu99;
368 | GCC_NO_COMMON_BLOCKS = YES;
369 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
370 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
371 | GCC_WARN_UNDECLARED_SELECTOR = YES;
372 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
373 | GCC_WARN_UNUSED_FUNCTION = YES;
374 | GCC_WARN_UNUSED_VARIABLE = YES;
375 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
376 | MACOSX_DEPLOYMENT_TARGET = 10.10;
377 | MTL_ENABLE_DEBUG_INFO = NO;
378 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator";
379 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
380 | SWIFT_VERSION = 4.0;
381 | TARGETED_DEVICE_FAMILY = "1,2,3,4";
382 | TVOS_DEPLOYMENT_TARGET = 9.0;
383 | VALIDATE_PRODUCT = YES;
384 | VERSIONING_SYSTEM = "apple-generic";
385 | VERSION_INFO_PREFIX = "";
386 | WATCHOS_DEPLOYMENT_TARGET = 2.2;
387 | };
388 | name = Release;
389 | };
390 | 09B036261C5E8029001EA5B7 /* Debug */ = {
391 | isa = XCBuildConfiguration;
392 | buildSettings = {
393 | COMBINE_HIDPI_IMAGES = YES;
394 | INFOPLIST_FILE = DipUITests/Info.plist;
395 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
396 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks @loader_path/../Frameworks";
397 | PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipUITests;
398 | PRODUCT_NAME = "$(TARGET_NAME)";
399 | STORYBOARD_NAME_PREFIX = NS;
400 | "STORYBOARD_NAME_PREFIX[sdk=appletvos*]" = TV;
401 | "STORYBOARD_NAME_PREFIX[sdk=appletvsimulator*]" = TV;
402 | "STORYBOARD_NAME_PREFIX[sdk=iphoneos*]" = UI;
403 | "STORYBOARD_NAME_PREFIX[sdk=iphonesimulator*]" = UI;
404 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator";
405 | TARGETED_DEVICE_FAMILY = "1,2,3";
406 | };
407 | name = Debug;
408 | };
409 | 09B036271C5E8029001EA5B7 /* Release */ = {
410 | isa = XCBuildConfiguration;
411 | buildSettings = {
412 | COMBINE_HIDPI_IMAGES = YES;
413 | INFOPLIST_FILE = DipUITests/Info.plist;
414 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
415 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks @loader_path/../Frameworks";
416 | PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipUITests;
417 | PRODUCT_NAME = "$(TARGET_NAME)";
418 | STORYBOARD_NAME_PREFIX = "";
419 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator";
420 | TARGETED_DEVICE_FAMILY = "1,2,3";
421 | };
422 | name = Release;
423 | };
424 | 09B0366C1C5E836B001EA5B7 /* Debug */ = {
425 | isa = XCBuildConfiguration;
426 | buildSettings = {
427 | "CODE_SIGN_IDENTITY[sdk=*]" = "";
428 | COMBINE_HIDPI_IMAGES = YES;
429 | DEFINES_MODULE = YES;
430 | DYLIB_COMPATIBILITY_VERSION = 1;
431 | DYLIB_CURRENT_VERSION = 1;
432 | DYLIB_INSTALL_NAME_BASE = "@rpath";
433 | FRAMEWORK_VERSION = A;
434 | INFOPLIST_FILE = DipUI/Info.plist;
435 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
437 | PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipUI;
438 | PRODUCT_NAME = DipUI;
439 | SKIP_INSTALL = YES;
440 | };
441 | name = Debug;
442 | };
443 | 09B0366D1C5E836B001EA5B7 /* Release */ = {
444 | isa = XCBuildConfiguration;
445 | buildSettings = {
446 | "CODE_SIGN_IDENTITY[sdk=*]" = "";
447 | COMBINE_HIDPI_IMAGES = YES;
448 | DEFINES_MODULE = YES;
449 | DYLIB_COMPATIBILITY_VERSION = 1;
450 | DYLIB_CURRENT_VERSION = 1;
451 | DYLIB_INSTALL_NAME_BASE = "@rpath";
452 | FRAMEWORK_VERSION = A;
453 | INFOPLIST_FILE = DipUI/Info.plist;
454 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
455 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
456 | PRODUCT_BUNDLE_IDENTIFIER = com.alisoftware.DipUI;
457 | PRODUCT_NAME = DipUI;
458 | SKIP_INSTALL = YES;
459 | };
460 | name = Release;
461 | };
462 | /* End XCBuildConfiguration section */
463 |
464 | /* Begin XCConfigurationList section */
465 | 09B036081C5E8028001EA5B7 /* Build configuration list for PBXProject "DipUI" */ = {
466 | isa = XCConfigurationList;
467 | buildConfigurations = (
468 | 09B036201C5E8029001EA5B7 /* Debug */,
469 | 09B036211C5E8029001EA5B7 /* Release */,
470 | );
471 | defaultConfigurationIsVisible = 0;
472 | defaultConfigurationName = Release;
473 | };
474 | 09B036251C5E8029001EA5B7 /* Build configuration list for PBXNativeTarget "DipUITests" */ = {
475 | isa = XCConfigurationList;
476 | buildConfigurations = (
477 | 09B036261C5E8029001EA5B7 /* Debug */,
478 | 09B036271C5E8029001EA5B7 /* Release */,
479 | );
480 | defaultConfigurationIsVisible = 0;
481 | defaultConfigurationName = Release;
482 | };
483 | 09B0366B1C5E836B001EA5B7 /* Build configuration list for PBXNativeTarget "DipUI" */ = {
484 | isa = XCConfigurationList;
485 | buildConfigurations = (
486 | 09B0366C1C5E836B001EA5B7 /* Debug */,
487 | 09B0366D1C5E836B001EA5B7 /* Release */,
488 | );
489 | defaultConfigurationIsVisible = 0;
490 | defaultConfigurationName = Release;
491 | };
492 | /* End XCConfigurationList section */
493 | };
494 | rootObject = 09B036051C5E8028001EA5B7 /* Project object */;
495 | }
496 |
--------------------------------------------------------------------------------