├── .gitignore ├── LICENSE ├── README.md ├── VIPER Coordinators ├── Application Coordinator.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ └── ___FILEBASENAME___.swift ├── Coordinator Protocol.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ └── ___FILEBASENAME___.swift ├── Interactor.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ ├── ___FILEBASENAME___Interactor.swift │ ├── ___FILEBASENAME___Models.swift │ └── ___FILEBASENAME___Protocols.swift └── Scene.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ ├── UIViewController │ ├── ___FILEBASENAME___Models.swift │ ├── ___FILEBASENAME___Presenter.swift │ ├── ___FILEBASENAME___Protocols.swift │ ├── ___FILEBASENAME___ViewController.storyboard │ └── ___FILEBASENAME___ViewController.swift │ └── UIViewControllerwithCoordinator │ ├── ___FILEBASENAME___Coordinator.swift │ ├── ___FILEBASENAME___Models.swift │ ├── ___FILEBASENAME___Presenter.swift │ ├── ___FILEBASENAME___Protocols.swift │ ├── ___FILEBASENAME___ViewController.storyboard │ └── ___FILEBASENAME___ViewController.swift └── install.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | Carthage/ 53 | #Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/screenshots 64 | 65 | .DS_Store 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Nodes Agency - iOS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![](https://raw.githubusercontent.com/nodes-ios/VIPERCoordinatorsXcodeFileTemplate/master/VIPER%20Coordinators/Scene.xctemplate/TemplateIcon.png) VIPER Coordinators Xcode File Template 2 | 3 | An Xcode file template that generates multiple files with boilerplate code required for setting up a scene using VIPER and Coordinators. 4 | 5 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/nodes-ios/VIPERCoordinatorsXcodeFileTemplate/blob/master/LICENSE) 6 | 7 | ## 📦 Installation 8 | 9 | 1. Clone this repository 10 | 2. `cd` to it in Terminal 11 | 3. Change permissions and run the install script 12 | 13 | ~~~ 14 | chmod 755 install.sh && ./install.sh 15 | ~~~ 16 | 17 | #### To remove old templates 18 | Go to /Library/Developer/Xcode/Templates/File Templates and delete the ones you don't need anymore. 19 | 20 | ## Usage 21 | 22 | 1. Open your Xcode project 23 | 2. Create a new file (`Cmd + N`) 24 | 3. Notice VIPER Coordinators in the left pane 25 | 26 | ## Known Issues 27 | 28 | Various current and previous issues and how to fix them. 29 | 30 | #### Coordinator Leak 31 | In all versions up to version 1.5.0 (not including) there was a memory leak due to a retain cycle between the presenter and the coordinator. 32 | 33 | This is the entire retain cycle: 34 | `Coordinator` **>** `Navigation Controller` **>** `View Controller` **>** `Presenter` **>** `Coordinator` 35 | 36 | ![](http://i.imgur.com/FqvGKYl.png) 37 | 38 | The steps to fix this are as follows: 39 | 40 | 1. Make the `YourCoordinatorInput` protocol a class protocol by appending `: class` to its declaration 41 | 2. Change the coordinator reference in the presetner (the property) to be a weak reference, ie. `weak var coordinator: YourCoordinatorInput?` 42 | 3. Update all code in presenter referencing coordinator with `?` to fix issues with the property now being optional 43 | 44 | To do all steps faster and automatically you can use Xcode's search and replace with regular expressions as follows: 45 | 46 | **Step 1** 47 | Search field: `protocol ([\w]*)CoordinatorInput \{` 48 | Replace field: `protocol $1CoordinatorInput: class \{` 49 | 50 | **Step 2** 51 | Search field: `let coordinator: ([\w]*)CoordinatorInput` 52 | Replace field: `weak var coordinator: $1CoordinatorInput?` 53 | 54 | **Step 3** (experimental, might need tweaks) 55 | Search field: `([\n]+[\s]*coordinator)\.(?!start)` 56 | Replace field: `$1?\.` 57 | 58 | ## 💥 How we use! 59 | 60 | Check it out [HERE](https://github.com/nodes-ios/Playbook/blob/master/ViperArchitecture.md) to see how we use this awesome pattern! 61 | 62 | ## 👥 Credits 63 | Made with ❤️ at [Nodes](http://nodesagency.com). 64 | 65 | ## 📄 License 66 | **VIPER Coordinators Xcode File Template** is available under the MIT license. See the [LICENSE](https://github.com/nodes-ios/VIPERCoordinatorsXcodeFileTemplate/blob/master/LICENSE) file for more info. 67 | -------------------------------------------------------------------------------- /VIPER Coordinators/Application Coordinator.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/VIPERCoordinatorsXcodeFileTemplate/476461dafabfef2b35d72e514a31eb182dbdea11/VIPER Coordinators/Application Coordinator.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /VIPER Coordinators/Application Coordinator.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/VIPERCoordinatorsXcodeFileTemplate/476461dafabfef2b35d72e514a31eb182dbdea11/VIPER Coordinators/Application Coordinator.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /VIPER Coordinators/Application Coordinator.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kind 6 | Xcode.IDEFoundation.TextSubstitutionFileTemplateKind 7 | Description 8 | Main application coordinator, designated to be used from within your app delegate. 9 | Summary 10 | Main application coordinator, designated to be used from within your app delegate 11 | SortOrder 12 | 30 13 | AllowedTypes 14 | 15 | public.swift-source 16 | 17 | DefaultCompletionName 18 | AppCoordinator 19 | MainTemplateFile 20 | ___FILEBASENAME___.swift 21 | 22 | 23 | -------------------------------------------------------------------------------- /VIPER Coordinators/Application Coordinator.xctemplate/___FILEBASENAME___.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | //___COPYRIGHT___ 7 | // 8 | 9 | import UIKit 10 | 11 | class ___FILEBASENAMEASIDENTIFIER___: Coordinator { 12 | 13 | let window: UIWindow 14 | var children: [Coordinator] = [] 15 | 16 | init(window: UIWindow) { 17 | self.window = window 18 | } 19 | 20 | func start() { 21 | // Perform initial application seutp. 22 | setupAfterLaunch() 23 | 24 | // Start your first flow here. For example, this is the 25 | // ideal place for deciding if you should show login or main flows. 26 | showMain() 27 | 28 | // Finally make the window key and visible. 29 | window.makeKeyAndVisible() 30 | } 31 | 32 | // MARK: - Flows - 33 | 34 | func showMain() { 35 | // Create your child coordinator here, add it as a child and start it. 36 | // Make sure you set the root view controller of the window. 37 | } 38 | 39 | // MARK: - Additional Setup - 40 | 41 | func setupAfterLaunch() { 42 | // Perform initial app setup after launch like analytics, integrations and more. 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /VIPER Coordinators/Coordinator Protocol.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/VIPERCoordinatorsXcodeFileTemplate/476461dafabfef2b35d72e514a31eb182dbdea11/VIPER Coordinators/Coordinator Protocol.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /VIPER Coordinators/Coordinator Protocol.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/VIPERCoordinatorsXcodeFileTemplate/476461dafabfef2b35d72e514a31eb182dbdea11/VIPER Coordinators/Coordinator Protocol.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /VIPER Coordinators/Coordinator Protocol.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kind 6 | Xcode.IDEFoundation.TextSubstitutionFileTemplateKind 7 | Description 8 | A default Coordinator protocol implementation. 9 | Summary 10 | A default Coordinator protocol implementation 11 | SortOrder 12 | 30 13 | AllowedTypes 14 | 15 | public.swift-source 16 | 17 | DefaultCompletionName 18 | Coordinator 19 | MainTemplateFile 20 | ___FILEBASENAME___.swift 21 | 22 | 23 | -------------------------------------------------------------------------------- /VIPER Coordinators/Coordinator Protocol.xctemplate/___FILEBASENAME___.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | //___COPYRIGHT___ 7 | // 8 | 9 | import UIKit 10 | 11 | protocol ___FILEBASENAMEASIDENTIFIER___: AnyObject { 12 | var children: [Coordinator] { get set } 13 | func start() 14 | } 15 | -------------------------------------------------------------------------------- /VIPER Coordinators/Interactor.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/VIPERCoordinatorsXcodeFileTemplate/476461dafabfef2b35d72e514a31eb182dbdea11/VIPER Coordinators/Interactor.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /VIPER Coordinators/Interactor.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/VIPERCoordinatorsXcodeFileTemplate/476461dafabfef2b35d72e514a31eb182dbdea11/VIPER Coordinators/Interactor.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /VIPER Coordinators/Interactor.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | Example 7 | Description 8 | This generates a new interactor. It consists of the interactr, protocols and models. 9 | Kind 10 | Xcode.IDEKit.TextSubstitutionFileTemplateKind 11 | Options 12 | 13 | 14 | Description 15 | The name of the interactor to create 16 | Identifier 17 | sceneName 18 | Name 19 | New Interactor Name: 20 | NotPersisted 21 | 22 | Required 23 | 24 | Type 25 | text 26 | 27 | 28 | Default 29 | ___VARIABLE_sceneName:identifier___ 30 | Identifier 31 | productName 32 | Type 33 | static 34 | 35 | 36 | Default 37 | ___VARIABLE_sceneName:identifier___Protocols 38 | Description 39 | The protocols file name 40 | Identifier 41 | protocolsName 42 | Name 43 | Protocols Name: 44 | Required 45 | 46 | Type 47 | static 48 | 49 | 50 | Default 51 | ___VARIABLE_sceneName:identifier___Interactor 52 | Description 53 | The interactor name 54 | Identifier 55 | interactorName 56 | Name 57 | Interactor Name: 58 | Required 59 | 60 | Type 61 | static 62 | 63 | 64 | Default 65 | ___VARIABLE_sceneName:identifier___Models 66 | Description 67 | The model file name 68 | Identifier 69 | modelFileName 70 | Name 71 | Models Name: 72 | Required 73 | 74 | Type 75 | static 76 | 77 | 78 | SortOrder 79 | 9 80 | Summary 81 | This generates a new interactor. 82 | AllowedTypes 83 | 84 | public.swift-source 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /VIPER Coordinators/Interactor.xctemplate/___FILEBASENAME___Interactor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class ___VARIABLE_sceneName___Interactor { 12 | // MARK: - Properties 13 | weak var output: ___VARIABLE_sceneName___InteractorOutput? 14 | 15 | // MARK: - Init 16 | init() { 17 | 18 | // Log init 19 | } 20 | 21 | deinit { 22 | // Log deinit 23 | } 24 | } 25 | 26 | // MARK: - Business Logic - 27 | 28 | // PRESENTER -> INTERACTOR 29 | extension ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___InteractorInput { 30 | } 31 | -------------------------------------------------------------------------------- /VIPER Coordinators/Interactor.xctemplate/___FILEBASENAME___Models.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum ___VARIABLE_sceneName___ { 12 | enum Request { } 13 | enum Response { } 14 | } 15 | 16 | extension ___VARIABLE_sceneName___.Request { 17 | 18 | } 19 | 20 | extension ___VARIABLE_sceneName___.Response { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /VIPER Coordinators/Interactor.xctemplate/___FILEBASENAME___Protocols.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // PRESENTER -> INTERACTOR 12 | protocol ___VARIABLE_sceneName___InteractorInput { 13 | // func perform(_ request: ___VARIABLE_sceneName___.Request.Work) 14 | } 15 | 16 | // INTERACTOR -> PRESENTER (indirect) 17 | protocol ___VARIABLE_sceneName___InteractorOutput: AnyObject { 18 | // func present(_ response: ___VARIABLE_sceneName___.Response.Work) 19 | } 20 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/VIPERCoordinatorsXcodeFileTemplate/476461dafabfef2b35d72e514a31eb182dbdea11/VIPER Coordinators/Scene.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/VIPERCoordinatorsXcodeFileTemplate/476461dafabfef2b35d72e514a31eb182dbdea11/VIPER Coordinators/Scene.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | MyScene 7 | Description 8 | This generates a new scene using clean architecture and coordinators. It consists of the view controller, presenter and optionally a coordinator. 9 | Kind 10 | Xcode.IDEKit.TextSubstitutionFileTemplateKind 11 | Options 12 | 13 | 14 | Description 15 | The name of the scene to create 16 | Identifier 17 | sceneName 18 | Name 19 | New Scene Name: 20 | NotPersisted 21 | 22 | Required 23 | 24 | Type 25 | text 26 | 27 | 28 | Default 29 | ___VARIABLE_sceneName:identifier___ 30 | Identifier 31 | productName 32 | Type 33 | static 34 | 35 | 36 | Default 37 | ___VARIABLE_sceneName:identifier___ViewController 38 | Description 39 | The view controller name 40 | Identifier 41 | viewControllerName 42 | Name 43 | View Controller Name: 44 | Required 45 | 46 | Type 47 | static 48 | 49 | 50 | Default 51 | ___VARIABLE_sceneName:identifier___Presenter 52 | Description 53 | The presenter name 54 | Identifier 55 | presenterName 56 | Name 57 | Presenter Name: 58 | Required 59 | 60 | Type 61 | static 62 | 63 | 64 | Default 65 | ___VARIABLE_sceneName:identifier___Coordinator 66 | Description 67 | The coordinator name 68 | Identifier 69 | coordinatorName 70 | Name 71 | Coordinator Name: 72 | Required 73 | 74 | Type 75 | static 76 | 77 | 78 | Default 79 | ___VARIABLE_sceneName:identifier___Models 80 | Description 81 | The model file name 82 | Identifier 83 | modelFileName 84 | Name 85 | Model File Name: 86 | Required 87 | 88 | Type 89 | static 90 | 91 | 92 | Default 93 | UIViewController 94 | Description 95 | What view controller class to subclass for the new scene 96 | FallbackHeader 97 | #import <UIKit/UIKit.h> 98 | Identifier 99 | viewControllerSubclass 100 | Name 101 | Subclass of: 102 | NotPersisted 103 | 104 | Required 105 | YES 106 | Type 107 | class 108 | Values 109 | 110 | UIViewController 111 | 112 | 113 | 114 | Default 115 | 116 | Description 117 | Wheter to create a Coordinator for this scene 118 | Identifier 119 | withCoordinator 120 | Name 121 | Also create a Coordinator 122 | Type 123 | checkbox 124 | 125 | 126 | Platforms 127 | 128 | com.apple.platform.iphoneos 129 | com.apple.platform.tvos 130 | 131 | SortOrder 132 | 9 133 | Summary 134 | This generates a new scene using clean architecture enhanced with coordinators. 135 | 136 | 137 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/UIViewController/___FILEBASENAME___Models.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum ___VARIABLE_sceneName___ { 12 | enum DisplayData { } 13 | 14 | enum Action { 15 | 16 | } 17 | 18 | enum Route { 19 | 20 | } 21 | } 22 | 23 | extension ___VARIABLE_sceneName___.DisplayData { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/UIViewController/___FILEBASENAME___Presenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class ___VARIABLE_sceneName___Presenter { 12 | // MARK: - Properties 13 | weak var coordinator: ___VARIABLE_sceneName___CoordinatorInput? 14 | weak var output: ___VARIABLE_sceneName___PresenterOutput? 15 | 16 | // MARK: - Init 17 | init(coordinator: ___VARIABLE_sceneName___CoordinatorInput) { 18 | self.coordinator = coordinator 19 | } 20 | } 21 | 22 | // MARK: - User Events - 23 | // ----------------------------------------------- 24 | // View input will be handled below. 25 | 26 | extension ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___PresenterInput { 27 | func viewCreated() { 28 | 29 | } 30 | 31 | func handle(_ action: ___VARIABLE_sceneName___.Action) { 32 | 33 | } 34 | } 35 | 36 | // MARK: - Presentation Logic - 37 | // ----------------------------------------------- 38 | // Interactor output implementation will go below. 39 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/UIViewController/___FILEBASENAME___Protocols.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | // ======== Coordinator ======== // 13 | 14 | // PRESENTER -> COORDINATOR 15 | protocol ___VARIABLE_sceneName___CoordinatorInput: AnyObject { 16 | func navigate(to route: ___VARIABLE_sceneName___.Route) 17 | } 18 | 19 | // ======== Presenter ======== // 20 | 21 | // VIEW -> PRESENTER 22 | protocol ___VARIABLE_sceneName___PresenterInput { 23 | func viewCreated() 24 | func handle(_ action: ___VARIABLE_sceneName___.Action) 25 | } 26 | 27 | // PRESENTER -> VIEW 28 | protocol ___VARIABLE_sceneName___PresenterOutput: AnyObject { 29 | // func display(_ displayModel: ___VARIABLE_sceneName___.DisplayData.Work) 30 | } 31 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/UIViewController/___FILEBASENAME___ViewController.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 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/UIViewController/___FILEBASENAME___ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ___VARIABLE_sceneName___ViewController: UIViewController { 12 | // MARK: - Outlets 13 | 14 | // MARK: - Properties 15 | private var presenter: ___VARIABLE_sceneName___PresenterInput! 16 | 17 | // MARK: - Init 18 | class func instantiate(with presenter: ___VARIABLE_sceneName___PresenterInput) -> ___VARIABLE_sceneName___ViewController { 19 | let name = "\(___VARIABLE_sceneName___ViewController.self)" 20 | let storyboard = UIStoryboard(name: name, bundle: nil) 21 | 22 | guard let vc = storyboard.instantiateViewController(withIdentifier: name) as? ___VARIABLE_sceneName___ViewController else { 23 | preconditionFailure("Unable to instantiate a ___VARIABLE_sceneName___ViewController with the name \(name)") 24 | } 25 | 26 | vc.presenter = presenter 27 | 28 | return vc 29 | } 30 | 31 | // MARK: - View Lifecycle - 32 | 33 | override func viewDidLoad() { 34 | super.viewDidLoad() 35 | presenter.viewCreated() 36 | } 37 | 38 | // MARK: - Callbacks - 39 | 40 | } 41 | 42 | // MARK: - Display Logic - 43 | 44 | // PRESENTER -> VIEW 45 | extension ___VARIABLE_sceneName___ViewController: ___VARIABLE_sceneName___PresenterOutput { 46 | 47 | } 48 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/UIViewControllerwithCoordinator/___FILEBASENAME___Coordinator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class ___VARIABLE_sceneName___Coordinator: Coordinator { 13 | // MARK: - Properties 14 | let navigationController: UINavigationController 15 | // NOTE: This array is used to retain child coordinators. Don't forget to 16 | // remove them when the coordinator is done. 17 | var children: [Coordinator] = [] 18 | // weak var delegate: ___VARIABLE_sceneName___CoordinatorDelegate? 19 | 20 | // MARK: - Init 21 | init(navigationController: UINavigationController) { 22 | self.navigationController = navigationController 23 | } 24 | 25 | func start() { 26 | let presenter = ___VARIABLE_sceneName___Presenter(coordinator: self) 27 | let vc = ___VARIABLE_sceneName___ViewController.instantiate(with: presenter) 28 | 29 | presenter.output = vc 30 | 31 | // FIXME: Display as you need 32 | // navigationController.setViewControllers([vc], animated: false) 33 | } 34 | } 35 | // MARK: - Navigation Callbacks 36 | // PRESENTER -> COORDINATOR 37 | extension ___VARIABLE_sceneName___Coordinator: ___VARIABLE_sceneName___CoordinatorInput { 38 | func navigate(to route: ___VARIABLE_sceneName___.Route) { 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/UIViewControllerwithCoordinator/___FILEBASENAME___Models.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum ___VARIABLE_sceneName___ { 12 | enum DisplayData { } 13 | 14 | enum Action { 15 | 16 | } 17 | 18 | enum Route { 19 | 20 | } 21 | } 22 | 23 | extension ___VARIABLE_sceneName___.DisplayData { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/UIViewControllerwithCoordinator/___FILEBASENAME___Presenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class ___VARIABLE_sceneName___Presenter { 12 | // MARK: - Properties 13 | weak var coordinator: ___VARIABLE_sceneName___CoordinatorInput? 14 | weak var output: ___VARIABLE_sceneName___PresenterOutput? 15 | 16 | // MARK: - Init 17 | init(coordinator: ___VARIABLE_sceneName___CoordinatorInput) { 18 | self.coordinator = coordinator 19 | } 20 | } 21 | 22 | // MARK: - User Events - 23 | // ----------------------------------------------- 24 | // View input will be handled below. 25 | 26 | extension ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___PresenterInput { 27 | func viewCreated() { 28 | 29 | } 30 | 31 | func handle(_ action: ___VARIABLE_sceneName___.Action) { 32 | 33 | } 34 | } 35 | 36 | // MARK: - Presentation Logic - 37 | // ----------------------------------------------- 38 | // Interactor output implementation will go below. 39 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/UIViewControllerwithCoordinator/___FILEBASENAME___Protocols.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | // ======== Coordinator ======== // 13 | 14 | //protocol ___VARIABLE_sceneName___CoordinatorDelegate: AnyObject { 15 | // func coordinator(_ coordinator: Coordinator, finishedWithSuccess success: Bool) 16 | //} 17 | 18 | // PRESENTER -> COORDINATOR 19 | protocol ___VARIABLE_sceneName___CoordinatorInput: AnyObject { 20 | func navigate(to route: ___VARIABLE_sceneName___.Route) 21 | } 22 | 23 | // ======== Presenter ======== // 24 | 25 | // VIEW -> PRESENTER 26 | protocol ___VARIABLE_sceneName___PresenterInput { 27 | func viewCreated() 28 | func handle(_ action: ___VARIABLE_sceneName___.Action) 29 | } 30 | 31 | // PRESENTER -> VIEW 32 | protocol ___VARIABLE_sceneName___PresenterOutput: AnyObject { 33 | // func display(_ displayModel: ___VARIABLE_sceneName___.DisplayData.Work) 34 | } 35 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/UIViewControllerwithCoordinator/___FILEBASENAME___ViewController.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 | -------------------------------------------------------------------------------- /VIPER Coordinators/Scene.xctemplate/UIViewControllerwithCoordinator/___FILEBASENAME___ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ___VARIABLE_sceneName___ViewController: UIViewController { 12 | // MARK: - Outlets 13 | 14 | // MARK: - Properties 15 | private var presenter: ___VARIABLE_sceneName___PresenterInput! 16 | 17 | // MARK: - Init 18 | class func instantiate(with presenter: ___VARIABLE_sceneName___PresenterInput) -> ___VARIABLE_sceneName___ViewController { 19 | let name = "\(___VARIABLE_sceneName___ViewController.self)" 20 | let storyboard = UIStoryboard(name: name, bundle: nil) 21 | 22 | guard let vc = storyboard.instantiateViewController(withIdentifier: name) as? ___VARIABLE_sceneName___ViewController else { 23 | preconditionFailure("Unable to instantiate a ___VARIABLE_sceneName___ViewController with the name \(name)") 24 | } 25 | 26 | vc.presenter = presenter 27 | 28 | return vc 29 | } 30 | 31 | // MARK: - View Lifecycle - 32 | 33 | override func viewDidLoad() { 34 | super.viewDidLoad() 35 | presenter.viewCreated() 36 | } 37 | 38 | // MARK: - Callbacks - 39 | 40 | } 41 | 42 | // MARK: - Display Logic - 43 | 44 | // PRESENTER -> VIEW 45 | extension ___VARIABLE_sceneName___ViewController: ___VARIABLE_sceneName___PresenterOutput { 46 | 47 | } 48 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASE_XCODE_DIR="${HOME}/Library/Developer/Xcode" 4 | TEMPLATES_XCODE_DIR="${BASE_XCODE_DIR}/Templates" 5 | FILE_TEMPLATES_XCODE_DIR="${TEMPLATES_XCODE_DIR}/File Templates" 6 | TEMPLATES_FOLDER_NAME="VIPER Coordinators" 7 | 8 | echo "Starting installation of VIPER Coordinators templates." 9 | 10 | # Check if templates dir exists 11 | if [ ! -d "${TEMPLATES_XCODE_DIR}" ]; then 12 | echo "Creating Templates directory, because it didn't exist." 13 | mkdir "${TEMPLATES_XCODE_DIR}" 14 | fi 15 | 16 | # Check if file templates dir exists 17 | if [ ! -d "${FILE_TEMPLATES_XCODE_DIR}" ]; then 18 | echo "Creating File Templates directory, because it didn't exist." 19 | mkdir "${FILE_TEMPLATES_XCODE_DIR}" 20 | fi 21 | 22 | # Check if templates exist 23 | if [ -d "${FILE_TEMPLATES_XCODE_DIR}/${TEMPLATES_FOLDER_NAME}" ]; then 24 | echo "Deleting previous ${TEMPLATES_FOLDER_NAME} directory." 25 | rm -rf "${FILE_TEMPLATES_XCODE_DIR}/${TEMPLATES_FOLDER_NAME}" 26 | fi 27 | 28 | # Copy the files 29 | echo "Copying template files." 30 | cp -r "${TEMPLATES_FOLDER_NAME}" "${FILE_TEMPLATES_XCODE_DIR}/" 31 | echo "VIPER Coordinators templates installation done." 32 | --------------------------------------------------------------------------------