diff --git a/DependencyInjection/ServiceLocator.swift b/DependencyInjection/ServiceLocator.swift new file mode 100644 index 0000000..c89ef81 --- /dev/null +++ b/DependencyInjection/ServiceLocator.swift @@ -0,0 +1,13 @@ +// +// ServiceLocator.swift +// +// Created by Jesus Martin Alonso on 13/11/2019. +// + +import Foundation + +//Protocol to implement by ServiceLocator objects that provides all the dependencies for the app +protocol ServiceLocator { + //Repositories + var myRepository: MyRepository {get} +} diff --git a/DependencyInjection/ServiceLocatorImpl.swift b/DependencyInjection/ServiceLocatorImpl.swift new file mode 100644 index 0000000..52db357 --- /dev/null +++ b/DependencyInjection/ServiceLocatorImpl.swift @@ -0,0 +1,19 @@ +// +// ServiceLocatorImpl.swift +// +// Created by Jesus Martin Alonso on 13/11/2019. +// + +import Foundation + +/// ServiceLocator default implementation. We use lazy vars to avoid loading all dependencies when ServiceLocator instance is created +class ServiceLocatorImpl: ServiceLocator { + + private lazy var remoteDataSource = { + MyRemoteDataSource() + }() + + lazy var myRepository: MyRepository = { + MyRepositoryImpl(remoteDataSource: remoteDataSource) + }() +} diff --git a/Module VIPER.xctemplate/Default/___FILEBASENAME___Presenter.swift b/Module VIPER.xctemplate/Default/___FILEBASENAME___Presenter.swift index d7e3674..9244130 100755 --- a/Module VIPER.xctemplate/Default/___FILEBASENAME___Presenter.swift +++ b/Module VIPER.xctemplate/Default/___FILEBASENAME___Presenter.swift @@ -10,7 +10,7 @@ import UIKit -class ___VARIABLE_productName:identifier___Presenter: ___VARIABLE_productName:identifier___PresenterProtocol { +class ___VARIABLE_productName:identifier___Presenter { weak private var view: ___VARIABLE_productName:identifier___ViewProtocol? var interactor: ___VARIABLE_productName:identifier___InteractorProtocol? @@ -23,3 +23,8 @@ class ___VARIABLE_productName:identifier___Presenter: ___VARIABLE_productName:id } } + +//MARK: - ___VARIABLE_productName:identifier___PresenterProtocol +extension ___VARIABLE_productName:identifier___Presenter: ___VARIABLE_productName:identifier___PresenterProtocol { + +} diff --git a/Module VIPER.xctemplate/Default/___FILEBASENAME___Protocols.swift b/Module VIPER.xctemplate/Default/___FILEBASENAME___Protocols.swift index adbd15f..1ef0b26 100755 --- a/Module VIPER.xctemplate/Default/___FILEBASENAME___Protocols.swift +++ b/Module VIPER.xctemplate/Default/___FILEBASENAME___Protocols.swift @@ -10,22 +10,22 @@ import Foundation -//MARK: Wireframe - +//MARK: - Wireframe protocol ___VARIABLE_productName:identifier___WireframeProtocol: class { } -//MARK: Presenter - +//MARK: - Presenter protocol ___VARIABLE_productName:identifier___PresenterProtocol: class { } -//MARK: Interactor - +//MARK: - Interactor protocol ___VARIABLE_productName:identifier___InteractorProtocol: class { var presenter: ___VARIABLE_productName:identifier___PresenterProtocol? { get set } } -//MARK: View - +//MARK: - View protocol ___VARIABLE_productName:identifier___ViewProtocol: class { var presenter: ___VARIABLE_productName:identifier___PresenterProtocol? { get set } diff --git a/Module VIPER.xctemplate/Default/___FILEBASENAME___Router.swift b/Module VIPER.xctemplate/Default/___FILEBASENAME___Router.swift index 30e0f72..ef1046e 100755 --- a/Module VIPER.xctemplate/Default/___FILEBASENAME___Router.swift +++ b/Module VIPER.xctemplate/Default/___FILEBASENAME___Router.swift @@ -13,12 +13,18 @@ import UIKit class ___VARIABLE_productName:identifier___Router: ___VARIABLE_productName:identifier___WireframeProtocol { weak var viewController: UIViewController? + let serviceLocator: ServiceLocator - static func createModule() -> UIViewController { + init(_ serviceLocator: ServiceLocator) { + self.serviceLocator = serviceLocator + } + + + static func createModule(serviceLocator: ServiceLocator) -> UIViewController { // Change to get view from storyboard if not using progammatic UI let view = ___VARIABLE_productName:identifier___ViewController(nibName: nil, bundle: nil) let interactor = ___VARIABLE_productName:identifier___Interactor() - let router = ___VARIABLE_productName:identifier___Router() + let router = ___VARIABLE_productName:identifier___Router(serviceLocator) let presenter = ___VARIABLE_productName:identifier___Presenter(interface: view, interactor: interactor, router: router) view.presenter = presenter diff --git a/Module VIPER.xctemplate/Default/___FILEBASENAME___ViewController.swift b/Module VIPER.xctemplate/Default/___FILEBASENAME___ViewController.swift index 23e417c..2c8bc46 100755 --- a/Module VIPER.xctemplate/Default/___FILEBASENAME___ViewController.swift +++ b/Module VIPER.xctemplate/Default/___FILEBASENAME___ViewController.swift @@ -10,7 +10,7 @@ import UIKit -class ___VARIABLE_productName:identifier___ViewController: UIViewController, ___VARIABLE_productName:identifier___ViewProtocol { +class ___VARIABLE_productName:identifier___ViewController: UIViewController { var presenter: ___VARIABLE_productName:identifier___PresenterProtocol? @@ -19,3 +19,8 @@ class ___VARIABLE_productName:identifier___ViewController: UIViewController, ___ } } + +//MARK: - ___VARIABLE_productName:identifier___ViewProtocol +extension ___VARIABLE_productName:identifier___ViewController: ___VARIABLE_productName:identifier___ViewProtocol{ + +} diff --git a/README.md b/README.md index 17d2eb8..a1273ee 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,15 @@ This is an example, we're creating a Login module: - [Default, without divide](/assets/defaultOutput.md) - [With divided Interactor (Input & Output)](/assets/inputOutput.md) +## Depedendency injection + +The `createModule` method of `Router` class receives a `ServiceLocator` object as argument. This object provides all the dependencies of the app and will be used to provides dependencies of the module. + +In this way, the service locator object is passed between modules. + +An example of ServiceLocator implementation can be found [here](DependencyInjection/ServiceLocatorImpl.swift) + + ## VIPER diagram overview ![Preview](/assets/viper_diagram.png) @@ -48,7 +57,7 @@ Would you like decide what will be the next feature? now, you can do it [here](h * [x] Create bash script to install more easy * [x] Divide Interactor protocol (Input & Output) (**NEW!** Version 1.1) * [x] Swift 4 & XCode 9 (**NEW!** Version 1.2) -* [ ] Add Dependency Injection Framework +* [x] Add Dependency Injection Framework (**NEW!** Service locator added) * [ ] Customize name of components * [ ] ~~Create groups in template~~ *(Only available for Project templates)* diff --git a/install.swift b/install.swift index d095874..1904898 100644 --- a/install.swift +++ b/install.swift @@ -29,9 +29,8 @@ func moveTemplate(){ printInConsole("✅ Template installed succesfully 🎉. Enjoy it 🙂") }else{ - - try _ = fileManager.replaceItemAt(URL(fileURLWithPath:"\(destinationPath)/\(templateName)"), withItemAt: URL(fileURLWithPath:templateName)) - + try fileManager.removeItem(atPath: "\(destinationPath)/\(templateName)") + try fileManager.copyItem(atPath: templateName, toPath: "\(destinationPath)/\(templateName)") printInConsole("✅ Template already exists. So has been replaced succesfully 🎉. Enjoy it 🙂") } } @@ -52,7 +51,7 @@ func shell(launchPath: String, arguments: [String]) -> String let data = pipe.fileHandleForReading.readDataToEndOfFile() let output = String(data: data, encoding: String.Encoding.utf8)! - if output.characters.count > 0 { + if output.count > 0 { //remove newline character. let lastIndex = output.index(before: output.endIndex) return String(output[output.startIndex ..< lastIndex])