Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DI framework as dependency - Part 2 #3

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Clean, Simple and Composable Routing for iOS Apps

This is the [first part](https://cassiuspacheco.com/clean-simple-and-composable-routing-for-ios-apps-ck7qv6kgo0063zns1gdpgwrue) of a series of blog posts about [Clean, Simple and Composable Routing for iOS Apps](https://hashnode.com/series/clean-simple-and-composable-routing-for-ios-apps-ck7vm42k401n4zis1wu4ar2od).
This is the [second part](https://cassiuspacheco.com/applying-dependency-injection-to-composable-routing-for-ios-apps-ck7v10xaz01h9zis1oksoe7h0) of a series of blog posts about [Clean, Simple and Composable Routing for iOS Apps](https://hashnode.com/series/clean-simple-and-composable-routing-for-ios-apps-ck7vm42k401n4zis1wu4ar2od).

## App's Flow Diagram

Expand Down
53 changes: 42 additions & 11 deletions RoutingExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 52;
objects = {

/* Begin PBXBuildFile section */
6A10678A241CDA3B00844681 /* WishlistTabRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A106788241CDA3B00844681 /* WishlistTabRoute.swift */; };
6A10678B241CDA3B00844681 /* ShopTabRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A106789241CDA3B00844681 /* ShopTabRoute.swift */; };
6A46A76E2419052200ED7426 /* ShopTabRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A46A76D2419052200ED7426 /* ShopTabRoute.swift */; };
6A46A770241905EB00ED7426 /* WishlistTabRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A46A76F241905EB00ED7426 /* WishlistTabRoute.swift */; };
6A46A773241908F400ED7426 /* DependencyGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A46A772241908F400ED7426 /* DependencyGraph.swift */; };
6A51EA05241DB801004FA2D0 /* DependencyContainer in Frameworks */ = {isa = PBXBuildFile; productRef = 6A51EA04241DB801004FA2D0 /* DependencyContainer */; };
6A61168224136AE30099C25F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A61168124136AE30099C25F /* AppDelegate.swift */; };
6A61168424136AE30099C25F /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A61168324136AE30099C25F /* SceneDelegate.swift */; };
6A61168624136AE30099C25F /* ShopViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A61168524136AE30099C25F /* ShopViewController.swift */; };
Expand Down Expand Up @@ -102,8 +104,9 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
6A106788241CDA3B00844681 /* WishlistTabRoute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WishlistTabRoute.swift; sourceTree = "<group>"; };
6A106789241CDA3B00844681 /* ShopTabRoute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShopTabRoute.swift; sourceTree = "<group>"; };
6A46A76D2419052200ED7426 /* ShopTabRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShopTabRoute.swift; sourceTree = "<group>"; };
6A46A76F241905EB00ED7426 /* WishlistTabRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WishlistTabRoute.swift; sourceTree = "<group>"; };
6A46A772241908F400ED7426 /* DependencyGraph.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DependencyGraph.swift; sourceTree = "<group>"; };
6A61167E24136AE30099C25F /* RoutingExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RoutingExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
6A61168124136AE30099C25F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
6A61168324136AE30099C25F /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -165,6 +168,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
6A51EA05241DB801004FA2D0 /* DependencyContainer in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -193,11 +197,11 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
6A106787241CDA3B00844681 /* Tabs */ = {
6A46A7712419085100ED7426 /* Tabs */ = {
isa = PBXGroup;
children = (
6A106788241CDA3B00844681 /* WishlistTabRoute.swift */,
6A106789241CDA3B00844681 /* ShopTabRoute.swift */,
6A46A76D2419052200ED7426 /* ShopTabRoute.swift */,
6A46A76F241905EB00ED7426 /* WishlistTabRoute.swift */,
);
path = Tabs;
sourceTree = "<group>";
Expand Down Expand Up @@ -230,6 +234,7 @@
children = (
6A61169124136AE50099C25F /* Info.plist */,
6A61168124136AE30099C25F /* AppDelegate.swift */,
6A46A772241908F400ED7426 /* DependencyGraph.swift */,
6A61168324136AE30099C25F /* SceneDelegate.swift */,
6A61168C24136AE50099C25F /* Assets.xcassets */,
6A61168E24136AE50099C25F /* LaunchScreen.storyboard */,
Expand Down Expand Up @@ -338,7 +343,7 @@
6AD8D5782413B81C00889F2D /* ProductRoute.swift */,
6AD8D5702413853A00889F2D /* SignUpRoute.swift */,
6AD8D5982413F7AA00889F2D /* SiriRoute.swift */,
6A106787241CDA3B00844681 /* Tabs */,
6A46A7712419085100ED7426 /* Tabs */,
);
path = Routes;
sourceTree = "<group>";
Expand Down Expand Up @@ -410,6 +415,9 @@
6AD8D5B624146A0F00889F2D /* PBXTargetDependency */,
);
name = RoutingExample;
packageProductDependencies = (
6A51EA04241DB801004FA2D0 /* DependencyContainer */,
);
productName = RoutingExample;
productReference = 6A61167E24136AE30099C25F /* RoutingExample.app */;
productType = "com.apple.product-type.application";
Expand Down Expand Up @@ -500,6 +508,9 @@
Base,
);
mainGroup = 6A61167524136AE30099C25F;
packageReferences = (
6A51EA03241DB801004FA2D0 /* XCRemoteSwiftPackageReference "DependencyContainer" */,
);
productRefGroup = 6A61167F24136AE30099C25F /* Products */;
projectDirPath = "";
projectRoot = "";
Expand Down Expand Up @@ -560,6 +571,7 @@
6AD8D58A2413D8C800889F2D /* ProductViewModel.swift in Sources */,
6A61168624136AE30099C25F /* ShopViewController.swift in Sources */,
6AD8D5722413853B00889F2D /* SignUpRoute.swift in Sources */,
6A46A773241908F400ED7426 /* DependencyGraph.swift in Sources */,
6AD8D57C2413D33D00889F2D /* DefaultRouter.swift in Sources */,
6AD8D5732413853B00889F2D /* LoginRoute.swift in Sources */,
6AD8D56B2413848700889F2D /* ModalTransition.swift in Sources */,
Expand All @@ -571,9 +583,10 @@
6AD8D56C2413848700889F2D /* Transition.swift in Sources */,
6A6116A624136C5C0099C25F /* MainTabBarController.swift in Sources */,
6A6116BD241372270099C25F /* LayoutHelper.swift in Sources */,
6A46A770241905EB00ED7426 /* WishlistTabRoute.swift in Sources */,
6AD8D5862413D73B00889F2D /* WishlistViewModel.swift in Sources */,
6A46A76E2419052200ED7426 /* ShopTabRoute.swift in Sources */,
6AD8D56D2413848700889F2D /* PushTransition.swift in Sources */,
6A10678A241CDA3B00844681 /* WishlistTabRoute.swift in Sources */,
6AD8D5992413F7AA00889F2D /* SiriRoute.swift in Sources */,
6AD8D5C82414BBAE00889F2D /* UIViewController.swift in Sources */,
6AD8D5752413B16300889F2D /* ForgottenPasswordRoute.swift in Sources */,
Expand All @@ -589,7 +602,6 @@
6AD8D5882413D83900889F2D /* PopUpViewModel.swift in Sources */,
6A61168424136AE30099C25F /* SceneDelegate.swift in Sources */,
6AD8D5772413B24000889F2D /* PopUpRoute.swift in Sources */,
6A10678B241CDA3B00844681 /* ShopTabRoute.swift in Sources */,
6A6116BF241372C70099C25F /* DefaultButton.swift in Sources */,
6AD8D5792413B81C00889F2D /* ProductRoute.swift in Sources */,
);
Expand Down Expand Up @@ -983,6 +995,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
6A51EA03241DB801004FA2D0 /* XCRemoteSwiftPackageReference "DependencyContainer" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/CassiusPacheco/DependencyContainer";
requirement = {
kind = exactVersion;
version = 0.1.0;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
6A51EA04241DB801004FA2D0 /* DependencyContainer */ = {
isa = XCSwiftPackageProductDependency;
package = 6A51EA03241DB801004FA2D0 /* XCRemoteSwiftPackageReference "DependencyContainer" */;
productName = DependencyContainer;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 6A61167624136AE30099C25F /* Project object */;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"object": {
"pins": [
{
"package": "DependencyContainer",
"repositoryURL": "https://github.com/CassiusPacheco/DependencyContainer",
"state": {
"branch": null,
"revision": "15049d95d20dabca6337c4c63c1ff98f3b776e07",
"version": "0.1.0"
}
}
]
},
"version": 1
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import UIKit

final class ForgottenPasswordViewController: UIViewController {
private let viewModel: ForgottenPasswordViewModel
private let viewModel: ForgottenPasswordViewModelInterface

init(viewModel: ForgottenPasswordViewModel) {
init(viewModel: ForgottenPasswordViewModelInterface) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@

import Foundation

final class ForgottenPasswordViewModel {
protocol ForgottenPasswordViewModelInterface {
func resetPasswordButtonTouchUpInside()
}

final class ForgottenPasswordViewModel: ForgottenPasswordViewModelInterface {
typealias Routes = PopUpRoute
private let router: Routes

Expand Down
4 changes: 2 additions & 2 deletions RoutingExample/Authentication/LoginViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import UIKit

final class LoginViewController: UIViewController {
private let viewModel: LoginViewModel
private let viewModel: LoginViewModelInterface

init(viewModel: LoginViewModel) {
init(viewModel: LoginViewModelInterface) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
Expand Down
8 changes: 7 additions & 1 deletion RoutingExample/Authentication/LoginViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@

import Foundation

final class LoginViewModel {
protocol LoginViewModelInterface {
func dismissButtonTouchUpInside()
func forgottenPasswordButtonTouchUpInside()
func signUpButtonTouchUpInside()
}

final class LoginViewModel: LoginViewModelInterface {
typealias Routes = LoginRoute & SignUpRoute & ForgottenPasswordRoute & Closable
private var router: Routes

Expand Down
4 changes: 2 additions & 2 deletions RoutingExample/Authentication/SignUpViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import UIKit

final class SignUpViewController: UIViewController {
private let viewModel: SignUpViewModel
private let viewModel: SignUpViewModelInterface

init(viewModel: SignUpViewModel) {
init(viewModel: SignUpViewModelInterface) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
Expand Down
7 changes: 6 additions & 1 deletion RoutingExample/Authentication/SignUpViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@

import Foundation

final class SignUpViewModel {
protocol SignUpViewModelInterface {
func forgottenPasswordButtonTouchUpInside()
func dismissButtonTouchUpInside()
}

final class SignUpViewModel: SignUpViewModelInterface {
typealias Routes = ForgottenPasswordRoute & Dismissable
private var router: Routes

Expand Down
48 changes: 48 additions & 0 deletions RoutingExample/DependencyGraph.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// DependencyGraph.swift
// RoutingExample
//
// Created by Cassius Pacheco on 11/3/20.
// Copyright © 2020 Cassius Pacheco. All rights reserved.
//

import Foundation
import DependencyContainer

final class DependencyGraph {
let container = DependencyContainer()

func registerDependencies() {
setupViewModels()
}

private func setupViewModels() {
container.register(LoginViewModelInterface.self) { (_, routes: LoginViewModel.Routes) in
return LoginViewModel(router: routes)
}

container.register(ForgottenPasswordViewModelInterface.self) { (_, routes: ForgottenPasswordViewModel.Routes) in
return ForgottenPasswordViewModel(router: routes)
}

container.register(SignUpViewModelInterface.self) { (_, routes: SignUpViewModel.Routes) in
return SignUpViewModel(router: routes)
}

container.register(PopUpViewModelInterface.self) { (_, message: String, routes: PopUpViewModel.Routes) in
return PopUpViewModel(message: message, router: routes)
}

container.register(ProductViewModelInterface.self) { (_, routes: ProductViewModel.Routes) in
return ProductViewModel(router: routes)
}

container.register(ShopViewModelInterface.self) { (_, routes: ShopViewModel.Routes) in
return ShopViewModel(router: routes)
}

container.register(WishlistViewModelInterface.self) { (_, routes: WishlistViewModel.Routes) in
return WishlistViewModel(router: routes)
}
}
}
4 changes: 2 additions & 2 deletions RoutingExample/PopUps/PopUpViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import UIKit

final class PopUpViewController: UIViewController {
private let viewModel: PopUpViewModel
private let viewModel: PopUpViewModelInterface

init(viewModel: PopUpViewModel) {
init(viewModel: PopUpViewModelInterface) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
Expand Down
8 changes: 7 additions & 1 deletion RoutingExample/PopUps/PopUpViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@

import Foundation

final class PopUpViewModel {
protocol PopUpViewModelInterface {
var message: String { get }

func dismissButtonTouchUpInside()
}

final class PopUpViewModel: PopUpViewModelInterface {
typealias Routes = Closable
private let router: Routes
let message: String
Expand Down
4 changes: 2 additions & 2 deletions RoutingExample/Product/ProductViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import UIKit
import IntentsUI

final class ProductViewController: UIViewController {
private let viewModel: ProductViewModel
private let viewModel: ProductViewModelInterface

init(viewModel: ProductViewModel) {
init(viewModel: ProductViewModelInterface) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
Expand Down
9 changes: 8 additions & 1 deletion RoutingExample/Product/ProductViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@
import Foundation
import IntentsUI

final class ProductViewModel {
protocol ProductViewModelInterface {
var siriButtonDelegate: INUIAddVoiceShortcutButtonDelegate { get }

func productButtonTouchUpInside()
func wishlistButtonTouchUpInside()
}

final class ProductViewModel: ProductViewModelInterface {
typealias Routes = ProductRoute & PopUpRoute & SiriRoute
private let router: Routes

Expand Down
3 changes: 2 additions & 1 deletion RoutingExample/Routing/Router.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import UIKit
import DependencyContainer

protocol Closable: class {
/// Closes the Router's root view controller using the transition used to show it.
Expand Down Expand Up @@ -50,5 +51,5 @@ protocol Router: Routable {
// Dependency Container example:
// https://github.com/CassiusPacheco/DependencyContainer
//
// var container: DependencyContainer { get }
var container: DependencyContainer { get }
}
5 changes: 4 additions & 1 deletion RoutingExample/Routing/Routers/DefaultRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@
//

import UIKit
import DependencyContainer

class DefaultRouter: NSObject, Router, Closable, Dismissable {
private let rootTransition: Transition
weak var root: UIViewController?
var container: DependencyContainer

init(rootTransition: Transition) {
init(rootTransition: Transition, container: DependencyContainer) {
self.rootTransition = rootTransition
self.container = container
}

deinit {
Expand Down
Loading