├── Clean Swift ├── Interactor.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ └── ___FILEBASENAME___Interactor.swift ├── Models.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ └── ___FILEBASENAME___Models.swift ├── Presenter.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ └── ___FILEBASENAME___Presenter.swift ├── Router.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ └── ___FILEBASENAME___Router.swift ├── Scene.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ ├── UICollectionViewController │ │ ├── ___FILEBASENAME___Interactor.swift │ │ ├── ___FILEBASENAME___Models.swift │ │ ├── ___FILEBASENAME___Presenter.swift │ │ ├── ___FILEBASENAME___Router.swift │ │ ├── ___FILEBASENAME___ViewController.swift │ │ └── ___FILEBASENAME___Worker.swift │ ├── UITableViewController │ │ ├── ___FILEBASENAME___Interactor.swift │ │ ├── ___FILEBASENAME___Models.swift │ │ ├── ___FILEBASENAME___Presenter.swift │ │ ├── ___FILEBASENAME___Router.swift │ │ ├── ___FILEBASENAME___ViewController.swift │ │ └── ___FILEBASENAME___Worker.swift │ └── UIViewController │ │ ├── ___FILEBASENAME___Interactor.swift │ │ ├── ___FILEBASENAME___Models.swift │ │ ├── ___FILEBASENAME___Presenter.swift │ │ ├── ___FILEBASENAME___Router.swift │ │ ├── ___FILEBASENAME___ViewController.swift │ │ └── ___FILEBASENAME___Worker.swift ├── Unit Tests.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ ├── ___FILEBASENAME___InteractorTests.swift │ ├── ___FILEBASENAME___PresenterTests.swift │ ├── ___FILEBASENAME___ViewControllerTests.swift │ └── ___FILEBASENAME___WorkerTests.swift ├── View Controller.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ ├── UICollectionViewController │ │ └── ___FILEBASENAME___ViewController.swift │ ├── UITableViewController │ │ └── ___FILEBASENAME___ViewController.swift │ └── UIViewController │ │ └── ___FILEBASENAME___ViewController.swift └── Worker.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ └── ___FILEBASENAME___Worker.swift ├── CleanSwiftExample ├── CleanSwiftExample.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcuserdata │ │ │ └── yoni.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── yoni.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── CleanSwiftExample │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── Model │ │ ├── Result.swift │ │ └── User.swift │ ├── SceneDelegate.swift │ ├── Screens │ │ ├── Home │ │ │ ├── HomeViewController.storyboard │ │ │ └── HomeViewController.swift │ │ └── Login │ │ │ ├── LoginInteractor.swift │ │ │ ├── LoginModels.swift │ │ │ ├── LoginPresenter.swift │ │ │ ├── LoginRouter.swift │ │ │ ├── LoginViewController.storyboard │ │ │ └── LoginViewController.swift │ └── ViewController.swift ├── CleanSwiftExampleTests │ ├── CleanSwiftExampleTests.swift │ └── Info.plist └── CleanSwiftExampleUITests │ ├── CleanSwiftExampleUITests.swift │ └── Info.plist ├── LICENSE └── README.md /Clean Swift/Interactor.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Interactor.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift/Interactor.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Interactor.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift/Interactor.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | MyScene 7 | Description 8 | This generates a new interactor using Uncle Bob's clean architecture. Your business logic goes here. 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___Interactor 38 | Description 39 | The interactor name 40 | Identifier 41 | interactorName 42 | Name 43 | Interactor Name: 44 | Required 45 | 46 | Type 47 | static 48 | 49 | 50 | Platforms 51 | 52 | com.apple.platform.iphoneos 53 | 54 | SortOrder 55 | 2 56 | Summary 57 | This generates a new interactor using Uncle Bob's clean architecture. Your business logic goes here. 58 | 59 | -------------------------------------------------------------------------------- /Clean Swift/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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___BusinessLogic { 16 | func doSomething(request: ___VARIABLE_sceneName___.Something.Request) 17 | // func doSomethingElse(request: ___VARIABLE_sceneName___.SomethingElse.Request) 18 | } 19 | 20 | protocol ___VARIABLE_sceneName___DataStore { 21 | //var name: String { get set } 22 | } 23 | 24 | class ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___BusinessLogic, ___VARIABLE_sceneName___DataStore { 25 | var presenter: ___VARIABLE_sceneName___PresentationLogic? 26 | var worker: ___VARIABLE_sceneName___Worker? 27 | //var name: String = "" 28 | 29 | // MARK: Do something (and send response to ___VARIABLE_sceneName___Presenter) 30 | 31 | func doSomething(request: ___VARIABLE_sceneName___.Something.Request) { 32 | worker = ___VARIABLE_sceneName___Worker() 33 | worker?.doSomeWork() 34 | 35 | let response = ___VARIABLE_sceneName___.Something.Response() 36 | presenter?.presentSomething(response: response) 37 | } 38 | // 39 | // func doSomethingElse(request: ___VARIABLE_sceneName___.SomethingElse.Request) { 40 | // worker = ___VARIABLE_sceneName___Worker() 41 | // worker?.doSomeOtherWork() 42 | // 43 | // let response = ___VARIABLE_sceneName___.SomethingElse.Response() 44 | // presenter?.presentSomethingElse(response: response) 45 | // } 46 | } 47 | -------------------------------------------------------------------------------- /Clean Swift/Models.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Models.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift/Models.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Models.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift/Models.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | MyScene 7 | Description 8 | This generates a new set of boundary models between the view controller, interactor, presenter, and router using Uncle Bob's clean architecture. 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 | Platforms 37 | 38 | com.apple.platform.iphoneos 39 | 40 | SortOrder 41 | 4 42 | Summary 43 | This generates a new set of boundary models between the view controller, interactor, presenter, and router using Uncle Bob's clean architecture. 44 | 45 | -------------------------------------------------------------------------------- /Clean Swift/Models.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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | enum ___VARIABLE_sceneName___ 16 | { 17 | // MARK: Use cases 18 | 19 | enum Something 20 | { 21 | struct Request 22 | { 23 | 24 | } 25 | 26 | struct Response 27 | { 28 | 29 | } 30 | 31 | struct ViewModel 32 | { 33 | 34 | } 35 | } 36 | 37 | // enum SomethingElse 38 | // { 39 | // struct Request 40 | // { 41 | // 42 | // } 43 | // 44 | // struct Response 45 | // { 46 | // 47 | // } 48 | // 49 | // struct ViewModel 50 | // { 51 | // 52 | // } 53 | // } 54 | } 55 | -------------------------------------------------------------------------------- /Clean Swift/Presenter.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Presenter.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift/Presenter.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Presenter.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift/Presenter.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | MyScene 7 | Description 8 | This generates a new presenter using Uncle Bob's clean architecture. Your presentation logic goes here. 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___Presenter 38 | Description 39 | The presenter name 40 | Identifier 41 | presenterName 42 | Name 43 | Presenter Name: 44 | Required 45 | 46 | Type 47 | static 48 | 49 | 50 | Platforms 51 | 52 | com.apple.platform.iphoneos 53 | 54 | SortOrder 55 | 3 56 | Summary 57 | This generates a new presenter using Uncle Bob's clean architecture. Your presentation logic goes here. 58 | 59 | -------------------------------------------------------------------------------- /Clean Swift/Presenter.xctemplate/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___PresentationLogic { 16 | func presentSomething(response: ___VARIABLE_sceneName___.Something.Response) 17 | } 18 | 19 | class ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___PresentationLogic { 20 | weak var viewController: ___VARIABLE_sceneName___DisplayLogic? 21 | 22 | // MARK: Parse and calc respnse from ___VARIABLE_sceneName___Interactor and send simple view model to ___VARIABLE_sceneName___ViewController to be displayed 23 | 24 | func presentSomething(response: ___VARIABLE_sceneName___.Something.Response) { 25 | let viewModel = ___VARIABLE_sceneName___.Something.ViewModel() 26 | viewController?.displaySomething(viewModel: viewModel) 27 | } 28 | // 29 | // func presentSomethingElse(response: ___VARIABLE_sceneName___.SomethingElse.Response) { 30 | // let viewModel = ___VARIABLE_sceneName___.SomethingElse.ViewModel() 31 | // viewController?.displaySomethingElse(viewModel: viewModel) 32 | // } 33 | } 34 | -------------------------------------------------------------------------------- /Clean Swift/Router.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Router.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift/Router.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Router.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift/Router.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | MyScene 7 | Description 8 | This generates a new router using Uncle Bob's clean architecture. You navigate to other scenes by presenting and dismissing other view controllers here. 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___Router 38 | Description 39 | The router name 40 | Identifier 41 | routerName 42 | Name 43 | Router Name: 44 | Required 45 | 46 | Type 47 | static 48 | 49 | 50 | Platforms 51 | 52 | com.apple.platform.iphoneos 53 | 54 | SortOrder 55 | 6 56 | Summary 57 | This generates a new router using Uncle Bob's clean architecture. You navigate to other scenes by presenting and dismissing other view controllers here. 58 | 59 | -------------------------------------------------------------------------------- /Clean Swift/Router.xctemplate/___FILEBASENAME___Router.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | @objc protocol ___VARIABLE_sceneName___RoutingLogic { 16 | //func routeToSomewhere(segue: UIStoryboardSegue?) 17 | } 18 | 19 | protocol ___VARIABLE_sceneName___DataPassing { 20 | var dataStore: ___VARIABLE_sceneName___DataStore? { get } 21 | } 22 | 23 | class ___VARIABLE_sceneName___Router: NSObject, ___VARIABLE_sceneName___RoutingLogic, ___VARIABLE_sceneName___DataPassing { 24 | weak var viewController: ___VARIABLE_sceneName___ViewController? 25 | var dataStore: ___VARIABLE_sceneName___DataStore? 26 | 27 | // MARK: Routing (navigating to other screens) 28 | 29 | //func routeToSomewhere(segue: UIStoryboardSegue?) { 30 | // if let segue = segue { 31 | // let destinationVC = segue.destination as! SomewhereViewController 32 | // var destinationDS = destinationVC.router!.dataStore! 33 | // passDataToSomewhere(source: dataStore!, destination: &destinationDS) 34 | // } else { 35 | // let storyboard = UIStoryboard(name: "Main", bundle: nil) 36 | // let destinationVC = storyboard.instantiateViewController(withIdentifier: "SomewhereViewController") as! SomewhereViewController 37 | // var destinationDS = destinationVC.router!.dataStore! 38 | // passDataToSomewhere(source: dataStore!, destination: &destinationDS) 39 | // navigateToSomewhere(source: viewController!, destination: destinationVC) 40 | // } 41 | //} 42 | 43 | // MARK: Navigation to other screen 44 | 45 | //func navigateToSomewhere(source: ___VARIABLE_sceneName___ViewController, destination: SomewhereViewController) { 46 | // source.show(destination, sender: nil) 47 | //} 48 | 49 | // MARK: Passing data to other screen 50 | 51 | // func passDataToSomewhere(source: ___VARIABLE_sceneName___DataStore, destination: inout SomewhereDataStore) { 52 | // destination.name = source.name 53 | // } 54 | } 55 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Scene.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Scene.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | MyScene 7 | Description 8 | This generates a new scene using Uncle Bob's clean architecture. It consists of the view controller, interactor, presenter, and router. You can then create individual workers to supplement the interactor. 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___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___Presenter 66 | Description 67 | The presenter name 68 | Identifier 69 | presenterName 70 | Name 71 | Presenter Name: 72 | Required 73 | 74 | Type 75 | static 76 | 77 | 78 | Default 79 | ___VARIABLE_sceneName:identifier___Router 80 | Description 81 | The router name 82 | Identifier 83 | routerName 84 | Name 85 | Router Name: 86 | Required 87 | 88 | Type 89 | static 90 | 91 | 92 | Default 93 | ___VARIABLE_sceneName:identifier___Configurator 94 | Description 95 | The configurator name 96 | Identifier 97 | configuratorName 98 | Name 99 | Configurator Name: 100 | Required 101 | 102 | Type 103 | static 104 | 105 | 106 | Default 107 | ___VARIABLE_sceneName:identifier___Worker 108 | Description 109 | The worker name 110 | Identifier 111 | workerName 112 | Name 113 | Worker Name: 114 | Required 115 | 116 | Type 117 | static 118 | 119 | 120 | Default 121 | ___VARIABLE_sceneName:identifier___Models 122 | Description 123 | The model file name 124 | Identifier 125 | modelFileName 126 | Name 127 | Model File Name: 128 | Required 129 | 130 | Type 131 | static 132 | 133 | 134 | Default 135 | UIViewController 136 | Description 137 | What view controller class to subclass for the new scene 138 | FallbackHeader 139 | #import <UIKit/UIKit.h> 140 | Identifier 141 | viewControllerSubclass 142 | Name 143 | Subclass of: 144 | NotPersisted 145 | 146 | Required 147 | YES 148 | Type 149 | class 150 | Values 151 | 152 | UIViewController 153 | UITableViewController 154 | UICollectionViewController 155 | 156 | 157 | 158 | Platforms 159 | 160 | com.apple.platform.iphoneos 161 | 162 | SortOrder 163 | 0 164 | Summary 165 | This generates a new scene using Uncle Bob's clean architecture. 166 | 167 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UICollectionViewController/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___BusinessLogic { 16 | func doSomething(request: ___VARIABLE_sceneName___.Something.Request) 17 | // func doSomethingElse(request: ___VARIABLE_sceneName___.SomethingElse.Request) 18 | } 19 | 20 | protocol ___VARIABLE_sceneName___DataStore { 21 | //var name: String { get set } 22 | } 23 | 24 | class ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___BusinessLogic, ___VARIABLE_sceneName___DataStore { 25 | var presenter: ___VARIABLE_sceneName___PresentationLogic? 26 | var worker: ___VARIABLE_sceneName___Worker? 27 | //var name: String = "" 28 | 29 | // MARK: Do something (and send response to ___VARIABLE_sceneName___Presenter) 30 | 31 | func doSomething(request: ___VARIABLE_sceneName___.Something.Request) { 32 | worker = ___VARIABLE_sceneName___Worker() 33 | worker?.doSomeWork() 34 | 35 | let response = ___VARIABLE_sceneName___.Something.Response() 36 | presenter?.presentSomething(response: response) 37 | } 38 | // 39 | // func doSomethingElse(request: ___VARIABLE_sceneName___.SomethingElse.Request) { 40 | // worker = ___VARIABLE_sceneName___Worker() 41 | // worker?.doSomeOtherWork() 42 | // 43 | // let response = ___VARIABLE_sceneName___.SomethingElse.Response() 44 | // presenter?.presentSomethingElse(response: response) 45 | // } 46 | } 47 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UICollectionViewController/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | enum ___VARIABLE_sceneName___ 16 | { 17 | // MARK: Use cases 18 | 19 | enum Something 20 | { 21 | struct Request 22 | { 23 | 24 | } 25 | 26 | struct Response 27 | { 28 | 29 | } 30 | 31 | struct ViewModel 32 | { 33 | 34 | } 35 | } 36 | 37 | // enum SomethingElse 38 | // { 39 | // struct Request 40 | // { 41 | // 42 | // } 43 | // 44 | // struct Response 45 | // { 46 | // 47 | // } 48 | // 49 | // struct ViewModel 50 | // { 51 | // 52 | // } 53 | // } 54 | } 55 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UICollectionViewController/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___PresentationLogic { 16 | func presentSomething(response: ___VARIABLE_sceneName___.Something.Response) 17 | } 18 | 19 | class ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___PresentationLogic { 20 | weak var viewController: ___VARIABLE_sceneName___DisplayLogic? 21 | 22 | // MARK: Parse and calc respnse from ___VARIABLE_sceneName___Interactor and send simple view model to ___VARIABLE_sceneName___ViewController to be displayed 23 | 24 | func presentSomething(response: ___VARIABLE_sceneName___.Something.Response) { 25 | let viewModel = ___VARIABLE_sceneName___.Something.ViewModel() 26 | viewController?.displaySomething(viewModel: viewModel) 27 | } 28 | // 29 | // func presentSomethingElse(response: ___VARIABLE_sceneName___.SomethingElse.Response) { 30 | // let viewModel = ___VARIABLE_sceneName___.SomethingElse.ViewModel() 31 | // viewController?.displaySomethingElse(viewModel: viewModel) 32 | // } 33 | } 34 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UICollectionViewController/___FILEBASENAME___Router.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | @objc protocol ___VARIABLE_sceneName___RoutingLogic { 16 | //func routeToSomewhere(segue: UIStoryboardSegue?) 17 | } 18 | 19 | protocol ___VARIABLE_sceneName___DataPassing { 20 | var dataStore: ___VARIABLE_sceneName___DataStore? { get } 21 | } 22 | 23 | class ___VARIABLE_sceneName___Router: NSObject, ___VARIABLE_sceneName___RoutingLogic, ___VARIABLE_sceneName___DataPassing { 24 | weak var viewController: ___VARIABLE_sceneName___ViewController? 25 | var dataStore: ___VARIABLE_sceneName___DataStore? 26 | 27 | // MARK: Routing (navigating to other screens) 28 | 29 | //func routeToSomewhere(segue: UIStoryboardSegue?) { 30 | // if let segue = segue { 31 | // let destinationVC = segue.destination as! SomewhereViewController 32 | // var destinationDS = destinationVC.router!.dataStore! 33 | // passDataToSomewhere(source: dataStore!, destination: &destinationDS) 34 | // } else { 35 | // let storyboard = UIStoryboard(name: "Main", bundle: nil) 36 | // let destinationVC = storyboard.instantiateViewController(withIdentifier: "SomewhereViewController") as! SomewhereViewController 37 | // var destinationDS = destinationVC.router!.dataStore! 38 | // passDataToSomewhere(source: dataStore!, destination: &destinationDS) 39 | // navigateToSomewhere(source: viewController!, destination: destinationVC) 40 | // } 41 | //} 42 | 43 | // MARK: Navigation to other screen 44 | 45 | //func navigateToSomewhere(source: ___VARIABLE_sceneName___ViewController, destination: SomewhereViewController) { 46 | // source.show(destination, sender: nil) 47 | //} 48 | 49 | // MARK: Passing data to other screen 50 | 51 | // func passDataToSomewhere(source: ___VARIABLE_sceneName___DataStore, destination: inout SomewhereDataStore) { 52 | // destination.name = source.name 53 | // } 54 | } 55 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UICollectionViewController/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___DisplayLogic: class { 16 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) 17 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) 18 | } 19 | 20 | class ___VARIABLE_sceneName___ViewController: UICollectionViewController, ___VARIABLE_sceneName___DisplayLogic { 21 | var interactor: ___VARIABLE_sceneName___BusinessLogic? 22 | var router: (NSObjectProtocol & ___VARIABLE_sceneName___RoutingLogic & ___VARIABLE_sceneName___DataPassing)? 23 | 24 | // MARK: Object lifecycle 25 | 26 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 27 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 28 | setup() 29 | } 30 | 31 | required init?(coder aDecoder: NSCoder) { 32 | super.init(coder: aDecoder) 33 | setup() 34 | } 35 | 36 | // MARK: - Setup Clean Code Design Pattern 37 | 38 | private func setup() { 39 | let viewController = self 40 | let interactor = ___VARIABLE_sceneName___Interactor() 41 | let presenter = ___VARIABLE_sceneName___Presenter() 42 | let router = ___VARIABLE_sceneName___Router() 43 | viewController.interactor = interactor 44 | viewController.router = router 45 | interactor.presenter = presenter 46 | presenter.viewController = viewController 47 | router.viewController = viewController 48 | router.dataStore = interactor 49 | } 50 | 51 | // MARK: - Routing 52 | 53 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 54 | if let scene = segue.identifier { 55 | let selector = NSSelectorFromString("routeTo\(scene)WithSegue:") 56 | if let router = router, router.responds(to: selector) { 57 | router.perform(selector, with: segue) 58 | } 59 | } 60 | } 61 | 62 | // MARK: - View lifecycle 63 | 64 | override func viewDidLoad() { 65 | super.viewDidLoad() 66 | doSomething() 67 | // doSomethingElse() 68 | } 69 | 70 | //MARK: - receive events from UI 71 | //@IBOutlet weak var nameTextField: UITextField! 72 | 73 | // @IBAction func cancelButtonTapped(_ sender: Any) { 74 | // 75 | // } 76 | // 77 | // @IBAction func confirmButtonTapped(_ sender: Any) { 78 | // 79 | // } 80 | // 81 | 82 | // MARK: - request data from ___VARIABLE_sceneName___Interactor 83 | 84 | //@IBOutlet weak var nameTextField: UITextField! 85 | 86 | func doSomething() { 87 | let request = ___VARIABLE_sceneName___.Something.Request() 88 | interactor?.doSomething(request: request) 89 | } 90 | // 91 | // func doSomethingElse() { 92 | // let request = ___VARIABLE_sceneName___.SomethingElse.Request() 93 | // interactor?.doSomethingElse(request: request) 94 | // } 95 | 96 | // MARK: - display view model from ___VARIABLE_sceneName___Presenter 97 | 98 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) { 99 | //nameTextField.text = viewModel.name 100 | } 101 | // 102 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) { 103 | // // do sometingElse with viewModel 104 | // } 105 | } 106 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UICollectionViewController/___FILEBASENAME___Worker.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | class ___VARIABLE_sceneName___Worker { 16 | func doSomeWork() { 17 | 18 | } 19 | // 20 | // func doSomeOtherWork() { 21 | // 22 | // } 23 | } 24 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UITableViewController/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___BusinessLogic { 16 | func doSomething(request: ___VARIABLE_sceneName___.Something.Request) 17 | // func doSomethingElse(request: ___VARIABLE_sceneName___.SomethingElse.Request) 18 | } 19 | 20 | protocol ___VARIABLE_sceneName___DataStore { 21 | //var name: String { get set } 22 | } 23 | 24 | class ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___BusinessLogic, ___VARIABLE_sceneName___DataStore { 25 | var presenter: ___VARIABLE_sceneName___PresentationLogic? 26 | var worker: ___VARIABLE_sceneName___Worker? 27 | //var name: String = "" 28 | 29 | // MARK: Do something (and send response to ___VARIABLE_sceneName___Presenter) 30 | 31 | func doSomething(request: ___VARIABLE_sceneName___.Something.Request) { 32 | worker = ___VARIABLE_sceneName___Worker() 33 | worker?.doSomeWork() 34 | 35 | let response = ___VARIABLE_sceneName___.Something.Response() 36 | presenter?.presentSomething(response: response) 37 | } 38 | // 39 | // func doSomethingElse(request: ___VARIABLE_sceneName___.SomethingElse.Request) { 40 | // worker = ___VARIABLE_sceneName___Worker() 41 | // worker?.doSomeOtherWork() 42 | // 43 | // let response = ___VARIABLE_sceneName___.SomethingElse.Response() 44 | // presenter?.presentSomethingElse(response: response) 45 | // } 46 | } 47 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UITableViewController/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | enum ___VARIABLE_sceneName___ 16 | { 17 | // MARK: Use cases 18 | 19 | enum Something 20 | { 21 | struct Request 22 | { 23 | 24 | } 25 | 26 | struct Response 27 | { 28 | 29 | } 30 | 31 | struct ViewModel 32 | { 33 | 34 | } 35 | } 36 | 37 | // enum SomethingElse 38 | // { 39 | // struct Request 40 | // { 41 | // 42 | // } 43 | // 44 | // struct Response 45 | // { 46 | // 47 | // } 48 | // 49 | // struct ViewModel 50 | // { 51 | // 52 | // } 53 | // } 54 | } 55 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UITableViewController/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___PresentationLogic { 16 | func presentSomething(response: ___VARIABLE_sceneName___.Something.Response) 17 | } 18 | 19 | class ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___PresentationLogic { 20 | weak var viewController: ___VARIABLE_sceneName___DisplayLogic? 21 | 22 | // MARK: Parse and calc respnse from ___VARIABLE_sceneName___Interactor and send simple view model to ___VARIABLE_sceneName___ViewController to be displayed 23 | 24 | func presentSomething(response: ___VARIABLE_sceneName___.Something.Response) { 25 | let viewModel = ___VARIABLE_sceneName___.Something.ViewModel() 26 | viewController?.displaySomething(viewModel: viewModel) 27 | } 28 | // 29 | // func presentSomethingElse(response: ___VARIABLE_sceneName___.SomethingElse.Response) { 30 | // let viewModel = ___VARIABLE_sceneName___.SomethingElse.ViewModel() 31 | // viewController?.displaySomethingElse(viewModel: viewModel) 32 | // } 33 | } 34 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UITableViewController/___FILEBASENAME___Router.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | @objc protocol ___VARIABLE_sceneName___RoutingLogic { 16 | //func routeToSomewhere(segue: UIStoryboardSegue?) 17 | } 18 | 19 | protocol ___VARIABLE_sceneName___DataPassing { 20 | var dataStore: ___VARIABLE_sceneName___DataStore? { get } 21 | } 22 | 23 | class ___VARIABLE_sceneName___Router: NSObject, ___VARIABLE_sceneName___RoutingLogic, ___VARIABLE_sceneName___DataPassing { 24 | weak var viewController: ___VARIABLE_sceneName___ViewController? 25 | var dataStore: ___VARIABLE_sceneName___DataStore? 26 | 27 | // MARK: Routing (navigating to other screens) 28 | 29 | //func routeToSomewhere(segue: UIStoryboardSegue?) { 30 | // if let segue = segue { 31 | // let destinationVC = segue.destination as! SomewhereViewController 32 | // var destinationDS = destinationVC.router!.dataStore! 33 | // passDataToSomewhere(source: dataStore!, destination: &destinationDS) 34 | // } else { 35 | // let storyboard = UIStoryboard(name: "Main", bundle: nil) 36 | // let destinationVC = storyboard.instantiateViewController(withIdentifier: "SomewhereViewController") as! SomewhereViewController 37 | // var destinationDS = destinationVC.router!.dataStore! 38 | // passDataToSomewhere(source: dataStore!, destination: &destinationDS) 39 | // navigateToSomewhere(source: viewController!, destination: destinationVC) 40 | // } 41 | //} 42 | 43 | // MARK: Navigation to other screen 44 | 45 | //func navigateToSomewhere(source: ___VARIABLE_sceneName___ViewController, destination: SomewhereViewController) { 46 | // source.show(destination, sender: nil) 47 | //} 48 | 49 | // MARK: Passing data to other screen 50 | 51 | // func passDataToSomewhere(source: ___VARIABLE_sceneName___DataStore, destination: inout SomewhereDataStore) { 52 | // destination.name = source.name 53 | // } 54 | } 55 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UITableViewController/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___DisplayLogic: class { 16 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) 17 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) 18 | } 19 | 20 | class ___VARIABLE_sceneName___ViewController: UITableViewController, ___VARIABLE_sceneName___DisplayLogic { 21 | var interactor: ___VARIABLE_sceneName___BusinessLogic? 22 | var router: (NSObjectProtocol & ___VARIABLE_sceneName___RoutingLogic & ___VARIABLE_sceneName___DataPassing)? 23 | 24 | // MARK: Object lifecycle 25 | 26 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 27 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 28 | setup() 29 | } 30 | 31 | required init?(coder aDecoder: NSCoder) { 32 | super.init(coder: aDecoder) 33 | setup() 34 | } 35 | 36 | // MARK: - Setup Clean Code Design Pattern 37 | 38 | private func setup() { 39 | let viewController = self 40 | let interactor = ___VARIABLE_sceneName___Interactor() 41 | let presenter = ___VARIABLE_sceneName___Presenter() 42 | let router = ___VARIABLE_sceneName___Router() 43 | viewController.interactor = interactor 44 | viewController.router = router 45 | interactor.presenter = presenter 46 | presenter.viewController = viewController 47 | router.viewController = viewController 48 | router.dataStore = interactor 49 | } 50 | 51 | // MARK: - Routing 52 | 53 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 54 | if let scene = segue.identifier { 55 | let selector = NSSelectorFromString("routeTo\(scene)WithSegue:") 56 | if let router = router, router.responds(to: selector) { 57 | router.perform(selector, with: segue) 58 | } 59 | } 60 | } 61 | 62 | // MARK: - View lifecycle 63 | 64 | override func viewDidLoad() { 65 | super.viewDidLoad() 66 | doSomething() 67 | // doSomethingElse() 68 | } 69 | 70 | //MARK: - receive events from UI 71 | //@IBOutlet weak var nameTextField: UITextField! 72 | 73 | // @IBAction func cancelButtonTapped(_ sender: Any) { 74 | // 75 | // } 76 | // 77 | // @IBAction func confirmButtonTapped(_ sender: Any) { 78 | // 79 | // } 80 | // 81 | 82 | // MARK: - request data from ___VARIABLE_sceneName___Interactor 83 | 84 | //@IBOutlet weak var nameTextField: UITextField! 85 | 86 | func doSomething() { 87 | let request = ___VARIABLE_sceneName___.Something.Request() 88 | interactor?.doSomething(request: request) 89 | } 90 | // 91 | // func doSomethingElse() { 92 | // let request = ___VARIABLE_sceneName___.SomethingElse.Request() 93 | // interactor?.doSomethingElse(request: request) 94 | // } 95 | 96 | // MARK: - display view model from ___VARIABLE_sceneName___Presenter 97 | 98 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) { 99 | //nameTextField.text = viewModel.name 100 | } 101 | // 102 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) { 103 | // // do sometingElse with viewModel 104 | // } 105 | } 106 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UITableViewController/___FILEBASENAME___Worker.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | class ___VARIABLE_sceneName___Worker { 16 | func doSomeWork() { 17 | 18 | } 19 | // 20 | // func doSomeOtherWork() { 21 | // 22 | // } 23 | } 24 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UIViewController/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___BusinessLogic { 16 | func doSomething(request: ___VARIABLE_sceneName___.Something.Request) 17 | // func doSomethingElse(request: ___VARIABLE_sceneName___.SomethingElse.Request) 18 | } 19 | 20 | protocol ___VARIABLE_sceneName___DataStore { 21 | //var name: String { get set } 22 | } 23 | 24 | class ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___BusinessLogic, ___VARIABLE_sceneName___DataStore { 25 | var presenter: ___VARIABLE_sceneName___PresentationLogic? 26 | var worker: ___VARIABLE_sceneName___Worker? 27 | //var name: String = "" 28 | 29 | // MARK: Do something (and send response to ___VARIABLE_sceneName___Presenter) 30 | 31 | func doSomething(request: ___VARIABLE_sceneName___.Something.Request) { 32 | worker = ___VARIABLE_sceneName___Worker() 33 | worker?.doSomeWork() 34 | 35 | let response = ___VARIABLE_sceneName___.Something.Response() 36 | presenter?.presentSomething(response: response) 37 | } 38 | // 39 | // func doSomethingElse(request: ___VARIABLE_sceneName___.SomethingElse.Request) { 40 | // worker = ___VARIABLE_sceneName___Worker() 41 | // worker?.doSomeOtherWork() 42 | // 43 | // let response = ___VARIABLE_sceneName___.SomethingElse.Response() 44 | // presenter?.presentSomethingElse(response: response) 45 | // } 46 | } 47 | -------------------------------------------------------------------------------- /Clean Swift/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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | enum ___VARIABLE_sceneName___ 16 | { 17 | // MARK: Use cases 18 | 19 | enum Something 20 | { 21 | struct Request 22 | { 23 | 24 | } 25 | 26 | struct Response 27 | { 28 | 29 | } 30 | 31 | struct ViewModel 32 | { 33 | 34 | } 35 | } 36 | 37 | // enum SomethingElse 38 | // { 39 | // struct Request 40 | // { 41 | // 42 | // } 43 | // 44 | // struct Response 45 | // { 46 | // 47 | // } 48 | // 49 | // struct ViewModel 50 | // { 51 | // 52 | // } 53 | // } 54 | } 55 | -------------------------------------------------------------------------------- /Clean Swift/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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___PresentationLogic { 16 | func presentSomething(response: ___VARIABLE_sceneName___.Something.Response) 17 | } 18 | 19 | class ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___PresentationLogic { 20 | weak var viewController: ___VARIABLE_sceneName___DisplayLogic? 21 | 22 | // MARK: Parse and calc respnse from ___VARIABLE_sceneName___Interactor and send simple view model to ___VARIABLE_sceneName___ViewController to be displayed 23 | 24 | func presentSomething(response: ___VARIABLE_sceneName___.Something.Response) { 25 | let viewModel = ___VARIABLE_sceneName___.Something.ViewModel() 26 | viewController?.displaySomething(viewModel: viewModel) 27 | } 28 | // 29 | // func presentSomethingElse(response: ___VARIABLE_sceneName___.SomethingElse.Response) { 30 | // let viewModel = ___VARIABLE_sceneName___.SomethingElse.ViewModel() 31 | // viewController?.displaySomethingElse(viewModel: viewModel) 32 | // } 33 | } 34 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UIViewController/___FILEBASENAME___Router.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | @objc protocol ___VARIABLE_sceneName___RoutingLogic { 16 | //func routeToSomewhere(segue: UIStoryboardSegue?) 17 | } 18 | 19 | protocol ___VARIABLE_sceneName___DataPassing { 20 | var dataStore: ___VARIABLE_sceneName___DataStore? { get } 21 | } 22 | 23 | class ___VARIABLE_sceneName___Router: NSObject, ___VARIABLE_sceneName___RoutingLogic, ___VARIABLE_sceneName___DataPassing { 24 | weak var viewController: ___VARIABLE_sceneName___ViewController? 25 | var dataStore: ___VARIABLE_sceneName___DataStore? 26 | 27 | // MARK: Routing (navigating to other screens) 28 | 29 | //func routeToSomewhere(segue: UIStoryboardSegue?) { 30 | // if let segue = segue { 31 | // let destinationVC = segue.destination as! SomewhereViewController 32 | // var destinationDS = destinationVC.router!.dataStore! 33 | // passDataToSomewhere(source: dataStore!, destination: &destinationDS) 34 | // } else { 35 | // let storyboard = UIStoryboard(name: "Main", bundle: nil) 36 | // let destinationVC = storyboard.instantiateViewController(withIdentifier: "SomewhereViewController") as! SomewhereViewController 37 | // var destinationDS = destinationVC.router!.dataStore! 38 | // passDataToSomewhere(source: dataStore!, destination: &destinationDS) 39 | // navigateToSomewhere(source: viewController!, destination: destinationVC) 40 | // } 41 | //} 42 | 43 | // MARK: Navigation to other screen 44 | 45 | //func navigateToSomewhere(source: ___VARIABLE_sceneName___ViewController, destination: SomewhereViewController) { 46 | // source.show(destination, sender: nil) 47 | //} 48 | 49 | // MARK: Passing data to other screen 50 | 51 | // func passDataToSomewhere(source: ___VARIABLE_sceneName___DataStore, destination: inout SomewhereDataStore) { 52 | // destination.name = source.name 53 | // } 54 | } 55 | -------------------------------------------------------------------------------- /Clean Swift/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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___DisplayLogic: class 16 | { 17 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) 18 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) 19 | } 20 | 21 | class ___VARIABLE_sceneName___ViewController: UIViewController, ___VARIABLE_sceneName___DisplayLogic { 22 | var interactor: ___VARIABLE_sceneName___BusinessLogic? 23 | var router: (NSObjectProtocol & ___VARIABLE_sceneName___RoutingLogic & ___VARIABLE_sceneName___DataPassing)? 24 | 25 | // MARK: Object lifecycle 26 | 27 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 28 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 29 | setup() 30 | } 31 | 32 | required init?(coder aDecoder: NSCoder) { 33 | super.init(coder: aDecoder) 34 | setup() 35 | } 36 | 37 | // MARK: - Setup Clean Code Design Pattern 38 | 39 | private func setup() { 40 | let viewController = self 41 | let interactor = ___VARIABLE_sceneName___Interactor() 42 | let presenter = ___VARIABLE_sceneName___Presenter() 43 | let router = ___VARIABLE_sceneName___Router() 44 | viewController.interactor = interactor 45 | viewController.router = router 46 | interactor.presenter = presenter 47 | presenter.viewController = viewController 48 | router.viewController = viewController 49 | router.dataStore = interactor 50 | } 51 | 52 | // MARK: - Routing 53 | 54 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 55 | if let scene = segue.identifier { 56 | let selector = NSSelectorFromString("routeTo\(scene)WithSegue:") 57 | if let router = router, router.responds(to: selector) { 58 | router.perform(selector, with: segue) 59 | } 60 | } 61 | } 62 | 63 | // MARK: - View lifecycle 64 | 65 | override func viewDidLoad() { 66 | super.viewDidLoad() 67 | doSomething() 68 | // doSomethingElse() 69 | } 70 | 71 | //MARK: - receive events from UI 72 | 73 | //@IBOutlet weak var nameTextField: UITextField! 74 | // 75 | // @IBAction func someButtonTapped(_ sender: Any) { 76 | // 77 | // } 78 | // 79 | // @IBAction func otherButtonTapped(_ sender: Any) { 80 | // 81 | // } 82 | 83 | // MARK: - request data from ___VARIABLE_sceneName___Interactor 84 | 85 | func doSomething() { 86 | let request = ___VARIABLE_sceneName___.Something.Request() 87 | interactor?.doSomething(request: request) 88 | } 89 | // 90 | // func doSomethingElse() { 91 | // let request = ___VARIABLE_sceneName___.SomethingElse.Request() 92 | // interactor?.doSomethingElse(request: request) 93 | // } 94 | 95 | // MARK: - display view model from ___VARIABLE_sceneName___Presenter 96 | 97 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) { 98 | //nameTextField.text = viewModel.name 99 | } 100 | // 101 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) { 102 | // // do sometingElse with viewModel 103 | // } 104 | } 105 | -------------------------------------------------------------------------------- /Clean Swift/Scene.xctemplate/UIViewController/___FILEBASENAME___Worker.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | class ___VARIABLE_sceneName___Worker { 16 | func doSomeWork() { 17 | 18 | } 19 | // 20 | // func doSomeOtherWork() { 21 | // 22 | // } 23 | } 24 | -------------------------------------------------------------------------------- /Clean Swift/Unit Tests.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Unit Tests.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift/Unit Tests.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Unit Tests.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift/Unit Tests.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | MyScene 7 | Description 8 | This generates unit tests for your scene using Uncle Bob's clean architecture. It consists of three test files for view controller, interactor, and presenter. 9 | Kind 10 | Xcode.IDEKit.TextSubstitutionFileTemplateKind 11 | Options 12 | 13 | 14 | Description 15 | The name of the scene to create tests for 16 | Identifier 17 | sceneName 18 | Name 19 | 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___ViewControllerTests 38 | Description 39 | The view controller tests name 40 | Identifier 41 | viewControllerTestsName 42 | Name 43 | View Controller Tests Name: 44 | Required 45 | 46 | Type 47 | static 48 | 49 | 50 | Default 51 | ___VARIABLE_sceneName:identifier___InteractorTests 52 | Description 53 | The interactor tests name 54 | Identifier 55 | interactorTestsName 56 | Name 57 | Interactor Tests Name: 58 | Required 59 | 60 | Type 61 | static 62 | 63 | 64 | Default 65 | ___VARIABLE_sceneName:identifier___PresenterTests 66 | Description 67 | The presenter tests name 68 | Identifier 69 | presenterTestsName 70 | Name 71 | Presenter Tests Name: 72 | Required 73 | 74 | Type 75 | static 76 | 77 | 78 | Default 79 | ___VARIABLE_sceneName:identifier___WorkerTests 80 | Description 81 | The worker tests name 82 | Identifier 83 | workerTestsName 84 | Name 85 | Worker Tests Name: 86 | Required 87 | 88 | Type 89 | static 90 | 91 | 92 | Platforms 93 | 94 | com.apple.platform.iphoneos 95 | 96 | SortOrder 97 | 7 98 | Summary 99 | This generates unit tests for your scene using Uncle Bob's clean architecture. 100 | 101 | -------------------------------------------------------------------------------- /Clean Swift/Unit Tests.xctemplate/___FILEBASENAME___InteractorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | @testable import ___PROJECTNAMEASIDENTIFIER___ 14 | import XCTest 15 | 16 | class ___VARIABLE_sceneName___InteractorTests: XCTestCase 17 | { 18 | // MARK: Subject under test 19 | 20 | var sut: ___VARIABLE_sceneName___Interactor! 21 | 22 | // MARK: - Test lifecycle 23 | 24 | override func setUp() { 25 | super.setUp() 26 | setup___VARIABLE_sceneName___Interactor() 27 | } 28 | 29 | override func tearDown() { 30 | super.tearDown() 31 | } 32 | 33 | // MARK: - Test setup 34 | 35 | func setup___VARIABLE_sceneName___Interactor() { 36 | sut = ___VARIABLE_sceneName___Interactor() 37 | } 38 | 39 | // MARK: - Test doubles 40 | 41 | class ___VARIABLE_sceneName___PresentationLogicSpy: ___VARIABLE_sceneName___PresentationLogic 42 | { 43 | var presentSomethingCalled = false 44 | 45 | func presentSomething(response: ___VARIABLE_sceneName___.Something.Response) { 46 | presentSomethingCalled = true 47 | } 48 | } 49 | 50 | // MARK: - Tests 51 | 52 | func testDoSomething() { 53 | // Given 54 | let spy = ___VARIABLE_sceneName___PresentationLogicSpy() 55 | sut.presenter = spy 56 | let request = ___VARIABLE_sceneName___.Something.Request() 57 | 58 | // When 59 | sut.doSomething(request: request) 60 | 61 | // Then 62 | XCTAssertTrue(spy.presentSomethingCalled, "doSomething(request:) should ask the presenter to format the result") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Clean Swift/Unit Tests.xctemplate/___FILEBASENAME___PresenterTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | @testable import ___PROJECTNAMEASIDENTIFIER___ 14 | import XCTest 15 | 16 | class ___VARIABLE_sceneName___PresenterTests: XCTestCase { 17 | // MARK: Subject under test 18 | 19 | var sut: ___VARIABLE_sceneName___Presenter! 20 | 21 | // MARK: - Test lifecycle 22 | 23 | override func setUp() { 24 | super.setUp() 25 | setup___VARIABLE_sceneName___Presenter() 26 | } 27 | 28 | override func tearDown() { 29 | super.tearDown() 30 | } 31 | 32 | // MARK: - Test setup 33 | 34 | func setup___VARIABLE_sceneName___Presenter() { 35 | sut = ___VARIABLE_sceneName___Presenter() 36 | } 37 | 38 | // MARK: - Test doubles 39 | 40 | class ___VARIABLE_sceneName___DisplayLogicSpy: ___VARIABLE_sceneName___DisplayLogic { 41 | var displaySomethingCalled = false 42 | 43 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) { 44 | displaySomethingCalled = true 45 | } 46 | } 47 | 48 | // MARK: - Tests 49 | 50 | func testPresentSomething() { 51 | // Given 52 | let spy = ___VARIABLE_sceneName___DisplayLogicSpy() 53 | sut.viewController = spy 54 | let response = ___VARIABLE_sceneName___.Something.Response() 55 | 56 | // When 57 | sut.presentSomething(response: response) 58 | 59 | // Then 60 | XCTAssertTrue(spy.displaySomethingCalled, "presentSomething(response:) should ask the view controller to display the result") 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Clean Swift/Unit Tests.xctemplate/___FILEBASENAME___ViewControllerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | @testable import ___PROJECTNAMEASIDENTIFIER___ 14 | import XCTest 15 | 16 | class ___VARIABLE_sceneName___ViewControllerTests: XCTestCase { 17 | // MARK: Subject under test 18 | 19 | var sut: ___VARIABLE_sceneName___ViewController! 20 | var window: UIWindow! 21 | 22 | // MARK: - Test lifecycle 23 | 24 | override func setUp() { 25 | super.setUp() 26 | window = UIWindow() 27 | setup___VARIABLE_sceneName___ViewController() 28 | } 29 | 30 | override func tearDown() { 31 | window = nil 32 | super.tearDown() 33 | } 34 | 35 | // MARK: - Test setup 36 | 37 | func setup___VARIABLE_sceneName___ViewController() { 38 | let bundle = Bundle.main 39 | let storyboard = UIStoryboard(name: "Main", bundle: bundle) 40 | sut = storyboard.instantiateViewController(withIdentifier: "___VARIABLE_sceneName___ViewController") as! ___VARIABLE_sceneName___ViewController 41 | } 42 | 43 | func loadView() { 44 | window.addSubview(sut.view) 45 | RunLoop.current.run(until: Date()) 46 | } 47 | 48 | // MARK: - Test doubles 49 | 50 | class ___VARIABLE_sceneName___BusinessLogicSpy: ___VARIABLE_sceneName___BusinessLogic { 51 | var doSomethingCalled = false 52 | 53 | func doSomething(request: ___VARIABLE_sceneName___.Something.Request) 54 | { 55 | doSomethingCalled = true 56 | } 57 | } 58 | 59 | // MARK: - Tests 60 | 61 | func testShouldDoSomethingWhenViewIsLoaded() { 62 | // Given 63 | let spy = ___VARIABLE_sceneName___BusinessLogicSpy() 64 | sut.interactor = spy 65 | 66 | // When 67 | loadView() 68 | 69 | // Then 70 | XCTAssertTrue(spy.doSomethingCalled, "viewDidLoad() should ask the interactor to do something") 71 | } 72 | 73 | func testDisplaySomething() { 74 | // Given 75 | let viewModel = ___VARIABLE_sceneName___.Something.ViewModel() 76 | 77 | // When 78 | loadView() 79 | sut.displaySomething(viewModel: viewModel) 80 | 81 | // Then 82 | //XCTAssertEqual(sut.nameTextField.text, "", "displaySomething(viewModel:) should update the name text field") 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Clean Swift/Unit Tests.xctemplate/___FILEBASENAME___WorkerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | @testable import ___PROJECTNAMEASIDENTIFIER___ 14 | import XCTest 15 | 16 | class ___VARIABLE_sceneName___WorkerTests: XCTestCase 17 | { 18 | // MARK: Subject under test 19 | 20 | var sut: ___VARIABLE_sceneName___Worker! 21 | 22 | // MARK: - Test lifecycle 23 | 24 | override func setUp() { 25 | super.setUp() 26 | setup___VARIABLE_sceneName___Worker() 27 | } 28 | 29 | override func tearDown() { 30 | super.tearDown() 31 | } 32 | 33 | // MARK: - Test setup 34 | 35 | func setup___VARIABLE_sceneName___Worker() { 36 | sut = ___VARIABLE_sceneName___Worker() 37 | } 38 | 39 | // MARK: - Test doubles 40 | 41 | // MARK: - Tests 42 | 43 | func testSomething() { 44 | // Given 45 | 46 | // When 47 | 48 | // Then 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Clean Swift/View Controller.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/View Controller.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift/View Controller.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/View Controller.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift/View Controller.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | MyScene 7 | Description 8 | This generates a new view controller using Uncle Bob's clean architecture. Your view/view controller logic goes here. 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 | UIViewController 52 | Description 53 | What view controller class to subclass for the new scene 54 | FallbackHeader 55 | #import <UIKit/UIKit.h> 56 | Identifier 57 | viewControllerSubclass 58 | Name 59 | Subclass of: 60 | NotPersisted 61 | 62 | Required 63 | YES 64 | Type 65 | class 66 | Values 67 | 68 | UIViewController 69 | UITableViewController 70 | UICollectionViewController 71 | 72 | 73 | 74 | Platforms 75 | 76 | com.apple.platform.iphoneos 77 | 78 | SortOrder 79 | 1 80 | Summary 81 | This generates a new view controller using Uncle Bob's clean architecture. Your view/view controller logic goes here. 82 | 83 | -------------------------------------------------------------------------------- /Clean Swift/View Controller.xctemplate/UICollectionViewController/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___DisplayLogic: class { 16 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) 17 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) 18 | } 19 | 20 | class ___VARIABLE_sceneName___ViewController: UICollectionViewController, ___VARIABLE_sceneName___DisplayLogic { 21 | var interactor: ___VARIABLE_sceneName___BusinessLogic? 22 | var router: (NSObjectProtocol & ___VARIABLE_sceneName___RoutingLogic & ___VARIABLE_sceneName___DataPassing)? 23 | 24 | // MARK: Object lifecycle 25 | 26 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 27 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 28 | setup() 29 | } 30 | 31 | required init?(coder aDecoder: NSCoder) { 32 | super.init(coder: aDecoder) 33 | setup() 34 | } 35 | 36 | // MARK: - Setup Clean Code Design Pattern 37 | 38 | private func setup() { 39 | let viewController = self 40 | let interactor = ___VARIABLE_sceneName___Interactor() 41 | let presenter = ___VARIABLE_sceneName___Presenter() 42 | let router = ___VARIABLE_sceneName___Router() 43 | viewController.interactor = interactor 44 | viewController.router = router 45 | interactor.presenter = presenter 46 | presenter.viewController = viewController 47 | router.viewController = viewController 48 | router.dataStore = interactor 49 | } 50 | 51 | // MARK: - Routing 52 | 53 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 54 | if let scene = segue.identifier { 55 | let selector = NSSelectorFromString("routeTo\(scene)WithSegue:") 56 | if let router = router, router.responds(to: selector) { 57 | router.perform(selector, with: segue) 58 | } 59 | } 60 | } 61 | 62 | // MARK: - View lifecycle 63 | 64 | override func viewDidLoad() { 65 | super.viewDidLoad() 66 | doSomething() 67 | // doSomethingElse() 68 | } 69 | 70 | //MARK: - receive events from UI 71 | //@IBOutlet weak var nameTextField: UITextField! 72 | 73 | // @IBAction func cancelButtonTapped(_ sender: Any) { 74 | // 75 | // } 76 | // 77 | // @IBAction func confirmButtonTapped(_ sender: Any) { 78 | // 79 | // } 80 | // 81 | 82 | // MARK: - request data from ___VARIABLE_sceneName___Interactor 83 | 84 | //@IBOutlet weak var nameTextField: UITextField! 85 | 86 | func doSomething() { 87 | let request = ___VARIABLE_sceneName___.Something.Request() 88 | interactor?.doSomething(request: request) 89 | } 90 | // 91 | // func doSomethingElse() { 92 | // let request = ___VARIABLE_sceneName___.SomethingElse.Request() 93 | // interactor?.doSomethingElse(request: request) 94 | // } 95 | 96 | // MARK: - display view model from ___VARIABLE_sceneName___Presenter 97 | 98 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) { 99 | //nameTextField.text = viewModel.name 100 | } 101 | // 102 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) { 103 | // // do sometingElse with viewModel 104 | // } 105 | } 106 | -------------------------------------------------------------------------------- /Clean Swift/View Controller.xctemplate/UITableViewController/___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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___DisplayLogic: class { 16 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) 17 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) 18 | } 19 | 20 | class ___VARIABLE_sceneName___ViewController: UITableViewController, ___VARIABLE_sceneName___DisplayLogic { 21 | var interactor: ___VARIABLE_sceneName___BusinessLogic? 22 | var router: (NSObjectProtocol & ___VARIABLE_sceneName___RoutingLogic & ___VARIABLE_sceneName___DataPassing)? 23 | 24 | // MARK: Object lifecycle 25 | 26 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 27 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 28 | setup() 29 | } 30 | 31 | required init?(coder aDecoder: NSCoder) { 32 | super.init(coder: aDecoder) 33 | setup() 34 | } 35 | 36 | // MARK: - Setup Clean Code Design Pattern 37 | 38 | private func setup() { 39 | let viewController = self 40 | let interactor = ___VARIABLE_sceneName___Interactor() 41 | let presenter = ___VARIABLE_sceneName___Presenter() 42 | let router = ___VARIABLE_sceneName___Router() 43 | viewController.interactor = interactor 44 | viewController.router = router 45 | interactor.presenter = presenter 46 | presenter.viewController = viewController 47 | router.viewController = viewController 48 | router.dataStore = interactor 49 | } 50 | 51 | // MARK: - Routing 52 | 53 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 54 | if let scene = segue.identifier { 55 | let selector = NSSelectorFromString("routeTo\(scene)WithSegue:") 56 | if let router = router, router.responds(to: selector) { 57 | router.perform(selector, with: segue) 58 | } 59 | } 60 | } 61 | 62 | // MARK: - View lifecycle 63 | 64 | override func viewDidLoad() { 65 | super.viewDidLoad() 66 | doSomething() 67 | // doSomethingElse() 68 | } 69 | 70 | //MARK: - receive events from UI 71 | //@IBOutlet weak var nameTextField: UITextField! 72 | 73 | // @IBAction func cancelButtonTapped(_ sender: Any) { 74 | // 75 | // } 76 | // 77 | // @IBAction func confirmButtonTapped(_ sender: Any) { 78 | // 79 | // } 80 | // 81 | 82 | //@IBOutlet weak var nameTextField: UITextField! 83 | 84 | func doSomething() { 85 | let request = ___VARIABLE_sceneName___.Something.Request() 86 | interactor?.doSomething(request: request) 87 | } 88 | // 89 | // func doSomethingElse() { 90 | // let request = ___VARIABLE_sceneName___.SomethingElse.Request() 91 | // interactor?.doSomethingElse(request: request) 92 | // } 93 | 94 | // MARK: - display view model from ___VARIABLE_sceneName___Presenter 95 | 96 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) { 97 | //nameTextField.text = viewModel.name 98 | } 99 | // 100 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) { 101 | // // do sometingElse with viewModel 102 | // } 103 | } 104 | -------------------------------------------------------------------------------- /Clean Swift/View Controller.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 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol ___VARIABLE_sceneName___DisplayLogic: class 16 | { 17 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) 18 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) 19 | } 20 | 21 | class ___VARIABLE_sceneName___ViewController: UIViewController, ___VARIABLE_sceneName___DisplayLogic { 22 | var interactor: ___VARIABLE_sceneName___BusinessLogic? 23 | var router: (NSObjectProtocol & ___VARIABLE_sceneName___RoutingLogic & ___VARIABLE_sceneName___DataPassing)? 24 | 25 | // MARK: Object lifecycle 26 | 27 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 28 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 29 | setup() 30 | } 31 | 32 | required init?(coder aDecoder: NSCoder) { 33 | super.init(coder: aDecoder) 34 | setup() 35 | } 36 | 37 | // MARK: - Setup Clean Code Design Pattern 38 | 39 | private func setup() { 40 | let viewController = self 41 | let interactor = ___VARIABLE_sceneName___Interactor() 42 | let presenter = ___VARIABLE_sceneName___Presenter() 43 | let router = ___VARIABLE_sceneName___Router() 44 | viewController.interactor = interactor 45 | viewController.router = router 46 | interactor.presenter = presenter 47 | presenter.viewController = viewController 48 | router.viewController = viewController 49 | router.dataStore = interactor 50 | } 51 | 52 | // MARK: - Routing 53 | 54 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 55 | if let scene = segue.identifier { 56 | let selector = NSSelectorFromString("routeTo\(scene)WithSegue:") 57 | if let router = router, router.responds(to: selector) { 58 | router.perform(selector, with: segue) 59 | } 60 | } 61 | } 62 | 63 | // MARK: - View lifecycle 64 | 65 | override func viewDidLoad() { 66 | super.viewDidLoad() 67 | doSomething() 68 | // doSomethingElse() 69 | } 70 | 71 | //MARK: - receive events from UI 72 | //@IBOutlet weak var nameTextField: UITextField! 73 | 74 | // @IBAction func cancelButtonTapped(_ sender: Any) { 75 | // 76 | // } 77 | // 78 | // @IBAction func confirmButtonTapped(_ sender: Any) { 79 | // 80 | // } 81 | // 82 | 83 | // MARK: - request data from ___VARIABLE_sceneName___Interactor 84 | 85 | //@IBOutlet weak var nameTextField: UITextField! 86 | 87 | func doSomething() { 88 | let request = ___VARIABLE_sceneName___.Something.Request() 89 | interactor?.doSomething(request: request) 90 | } 91 | // 92 | // func doSomethingElse() { 93 | // let request = ___VARIABLE_sceneName___.SomethingElse.Request() 94 | // interactor?.doSomethingElse(request: request) 95 | // } 96 | 97 | // MARK: - display view model from ___VARIABLE_sceneName___Presenter 98 | 99 | func displaySomething(viewModel: ___VARIABLE_sceneName___.Something.ViewModel) { 100 | //nameTextField.text = viewModel.name 101 | } 102 | // 103 | // func displaySomethingElse(viewModel: ___VARIABLE_sceneName___.SomethingElse.ViewModel) { 104 | // // do sometingElse with viewModel 105 | // } 106 | } 107 | -------------------------------------------------------------------------------- /Clean Swift/Worker.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Worker.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift/Worker.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/Clean Swift/Worker.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift/Worker.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | MyScene 7 | Description 8 | This generates a new worker to perform your specific business logic. 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___Worker 38 | Description 39 | The worker name 40 | Identifier 41 | workerName 42 | Name 43 | Worker Name: 44 | Required 45 | 46 | Type 47 | static 48 | 49 | 50 | Platforms 51 | 52 | com.apple.platform.iphoneos 53 | 54 | SortOrder 55 | 5 56 | Summary 57 | This generates a new worker to perform your specific business logic. 58 | 59 | -------------------------------------------------------------------------------- /Clean Swift/Worker.xctemplate/___FILEBASENAME___Worker.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | class ___VARIABLE_sceneName___Worker { 16 | func doSomeWork() { 17 | 18 | } 19 | // 20 | // func doSomeOtherWork() { 21 | // 22 | // } 23 | } 24 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E90CB4B4254B8C3C0083ECD3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90CB4B3254B8C3C0083ECD3 /* AppDelegate.swift */; }; 11 | E90CB4B6254B8C3C0083ECD3 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90CB4B5254B8C3C0083ECD3 /* SceneDelegate.swift */; }; 12 | E90CB4B8254B8C3C0083ECD3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90CB4B7254B8C3C0083ECD3 /* ViewController.swift */; }; 13 | E90CB4BB254B8C3C0083ECD3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E90CB4B9254B8C3C0083ECD3 /* Main.storyboard */; }; 14 | E90CB4BD254B8C3F0083ECD3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E90CB4BC254B8C3F0083ECD3 /* Assets.xcassets */; }; 15 | E90CB4C0254B8C3F0083ECD3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E90CB4BE254B8C3F0083ECD3 /* LaunchScreen.storyboard */; }; 16 | E90CB4CB254B8C3F0083ECD3 /* CleanSwiftExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90CB4CA254B8C3F0083ECD3 /* CleanSwiftExampleTests.swift */; }; 17 | E90CB4D6254B8C3F0083ECD3 /* CleanSwiftExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90CB4D5254B8C3F0083ECD3 /* CleanSwiftExampleUITests.swift */; }; 18 | E90CB4ED254B8C6C0083ECD3 /* LoginPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90CB4E7254B8C6C0083ECD3 /* LoginPresenter.swift */; }; 19 | E90CB4EF254B8C6C0083ECD3 /* LoginRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90CB4E9254B8C6C0083ECD3 /* LoginRouter.swift */; }; 20 | E90CB4F0254B8C6C0083ECD3 /* LoginModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90CB4EA254B8C6C0083ECD3 /* LoginModels.swift */; }; 21 | E90CB4F1254B8C6C0083ECD3 /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90CB4EB254B8C6C0083ECD3 /* LoginViewController.swift */; }; 22 | E90CB4F2254B8C6C0083ECD3 /* LoginInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90CB4EC254B8C6C0083ECD3 /* LoginInteractor.swift */; }; 23 | E94DB10B254DFAC2009215FA /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = E94DB10A254DFAC2009215FA /* User.swift */; }; 24 | E94DB122254E19A5009215FA /* LoginViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E94DB121254E19A5009215FA /* LoginViewController.storyboard */; }; 25 | E94DB12B254E1AF1009215FA /* HomeViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E94DB12A254E1AF1009215FA /* HomeViewController.storyboard */; }; 26 | E94DB130254E1B02009215FA /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E94DB12F254E1B02009215FA /* HomeViewController.swift */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | E90CB4C7254B8C3F0083ECD3 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = E90CB4A8254B8C3C0083ECD3 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = E90CB4AF254B8C3C0083ECD3; 35 | remoteInfo = CleanSwiftExample; 36 | }; 37 | E90CB4D2254B8C3F0083ECD3 /* PBXContainerItemProxy */ = { 38 | isa = PBXContainerItemProxy; 39 | containerPortal = E90CB4A8254B8C3C0083ECD3 /* Project object */; 40 | proxyType = 1; 41 | remoteGlobalIDString = E90CB4AF254B8C3C0083ECD3; 42 | remoteInfo = CleanSwiftExample; 43 | }; 44 | /* End PBXContainerItemProxy section */ 45 | 46 | /* Begin PBXFileReference section */ 47 | E90CB4B0254B8C3C0083ECD3 /* CleanSwiftExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CleanSwiftExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | E90CB4B3254B8C3C0083ECD3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 49 | E90CB4B5254B8C3C0083ECD3 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 50 | E90CB4B7254B8C3C0083ECD3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 51 | E90CB4BA254B8C3C0083ECD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 52 | E90CB4BC254B8C3F0083ECD3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 53 | E90CB4BF254B8C3F0083ECD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 54 | E90CB4C1254B8C3F0083ECD3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | E90CB4C6254B8C3F0083ECD3 /* CleanSwiftExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CleanSwiftExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | E90CB4CA254B8C3F0083ECD3 /* CleanSwiftExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CleanSwiftExampleTests.swift; sourceTree = ""; }; 57 | E90CB4CC254B8C3F0083ECD3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | E90CB4D1254B8C3F0083ECD3 /* CleanSwiftExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CleanSwiftExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | E90CB4D5254B8C3F0083ECD3 /* CleanSwiftExampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CleanSwiftExampleUITests.swift; sourceTree = ""; }; 60 | E90CB4D7254B8C3F0083ECD3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | E90CB4E7254B8C6C0083ECD3 /* LoginPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginPresenter.swift; sourceTree = ""; }; 62 | E90CB4E9254B8C6C0083ECD3 /* LoginRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginRouter.swift; sourceTree = ""; }; 63 | E90CB4EA254B8C6C0083ECD3 /* LoginModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginModels.swift; sourceTree = ""; }; 64 | E90CB4EB254B8C6C0083ECD3 /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = ""; }; 65 | E90CB4EC254B8C6C0083ECD3 /* LoginInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginInteractor.swift; sourceTree = ""; }; 66 | E94DB10A254DFAC2009215FA /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; 67 | E94DB121254E19A5009215FA /* LoginViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LoginViewController.storyboard; sourceTree = ""; }; 68 | E94DB12A254E1AF1009215FA /* HomeViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = HomeViewController.storyboard; sourceTree = ""; }; 69 | E94DB12F254E1B02009215FA /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = ""; }; 70 | /* End PBXFileReference section */ 71 | 72 | /* Begin PBXFrameworksBuildPhase section */ 73 | E90CB4AD254B8C3C0083ECD3 /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | E90CB4C3254B8C3F0083ECD3 /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | E90CB4CE254B8C3F0083ECD3 /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | ); 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | /* End PBXFrameworksBuildPhase section */ 95 | 96 | /* Begin PBXGroup section */ 97 | E90CB4A7254B8C3C0083ECD3 = { 98 | isa = PBXGroup; 99 | children = ( 100 | E90CB4B2254B8C3C0083ECD3 /* CleanSwiftExample */, 101 | E90CB4C9254B8C3F0083ECD3 /* CleanSwiftExampleTests */, 102 | E90CB4D4254B8C3F0083ECD3 /* CleanSwiftExampleUITests */, 103 | E90CB4B1254B8C3C0083ECD3 /* Products */, 104 | ); 105 | sourceTree = ""; 106 | }; 107 | E90CB4B1254B8C3C0083ECD3 /* Products */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | E90CB4B0254B8C3C0083ECD3 /* CleanSwiftExample.app */, 111 | E90CB4C6254B8C3F0083ECD3 /* CleanSwiftExampleTests.xctest */, 112 | E90CB4D1254B8C3F0083ECD3 /* CleanSwiftExampleUITests.xctest */, 113 | ); 114 | name = Products; 115 | sourceTree = ""; 116 | }; 117 | E90CB4B2254B8C3C0083ECD3 /* CleanSwiftExample */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | E94DB109254DFAA7009215FA /* Model */, 121 | E94DB10F254DFAD7009215FA /* Screens */, 122 | E90CB4B3254B8C3C0083ECD3 /* AppDelegate.swift */, 123 | E90CB4B5254B8C3C0083ECD3 /* SceneDelegate.swift */, 124 | E90CB4B7254B8C3C0083ECD3 /* ViewController.swift */, 125 | E90CB4B9254B8C3C0083ECD3 /* Main.storyboard */, 126 | E90CB4BC254B8C3F0083ECD3 /* Assets.xcassets */, 127 | E90CB4BE254B8C3F0083ECD3 /* LaunchScreen.storyboard */, 128 | E90CB4C1254B8C3F0083ECD3 /* Info.plist */, 129 | ); 130 | path = CleanSwiftExample; 131 | sourceTree = ""; 132 | }; 133 | E90CB4C9254B8C3F0083ECD3 /* CleanSwiftExampleTests */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | E90CB4CA254B8C3F0083ECD3 /* CleanSwiftExampleTests.swift */, 137 | E90CB4CC254B8C3F0083ECD3 /* Info.plist */, 138 | ); 139 | path = CleanSwiftExampleTests; 140 | sourceTree = ""; 141 | }; 142 | E90CB4D4254B8C3F0083ECD3 /* CleanSwiftExampleUITests */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | E90CB4D5254B8C3F0083ECD3 /* CleanSwiftExampleUITests.swift */, 146 | E90CB4D7254B8C3F0083ECD3 /* Info.plist */, 147 | ); 148 | path = CleanSwiftExampleUITests; 149 | sourceTree = ""; 150 | }; 151 | E90CB4E6254B8C550083ECD3 /* Login */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | E94DB121254E19A5009215FA /* LoginViewController.storyboard */, 155 | E90CB4EB254B8C6C0083ECD3 /* LoginViewController.swift */, 156 | E90CB4EC254B8C6C0083ECD3 /* LoginInteractor.swift */, 157 | E90CB4E7254B8C6C0083ECD3 /* LoginPresenter.swift */, 158 | E90CB4EA254B8C6C0083ECD3 /* LoginModels.swift */, 159 | E90CB4E9254B8C6C0083ECD3 /* LoginRouter.swift */, 160 | ); 161 | path = Login; 162 | sourceTree = ""; 163 | }; 164 | E94DB109254DFAA7009215FA /* Model */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | E94DB10A254DFAC2009215FA /* User.swift */, 168 | ); 169 | path = Model; 170 | sourceTree = ""; 171 | }; 172 | E94DB10F254DFAD7009215FA /* Screens */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | E90CB4E6254B8C550083ECD3 /* Login */, 176 | E94DB129254E1AD3009215FA /* Home */, 177 | ); 178 | path = Screens; 179 | sourceTree = ""; 180 | }; 181 | E94DB129254E1AD3009215FA /* Home */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | E94DB12A254E1AF1009215FA /* HomeViewController.storyboard */, 185 | E94DB12F254E1B02009215FA /* HomeViewController.swift */, 186 | ); 187 | path = Home; 188 | sourceTree = ""; 189 | }; 190 | /* End PBXGroup section */ 191 | 192 | /* Begin PBXNativeTarget section */ 193 | E90CB4AF254B8C3C0083ECD3 /* CleanSwiftExample */ = { 194 | isa = PBXNativeTarget; 195 | buildConfigurationList = E90CB4DA254B8C3F0083ECD3 /* Build configuration list for PBXNativeTarget "CleanSwiftExample" */; 196 | buildPhases = ( 197 | E90CB4AC254B8C3C0083ECD3 /* Sources */, 198 | E90CB4AD254B8C3C0083ECD3 /* Frameworks */, 199 | E90CB4AE254B8C3C0083ECD3 /* Resources */, 200 | ); 201 | buildRules = ( 202 | ); 203 | dependencies = ( 204 | ); 205 | name = CleanSwiftExample; 206 | productName = CleanSwiftExample; 207 | productReference = E90CB4B0254B8C3C0083ECD3 /* CleanSwiftExample.app */; 208 | productType = "com.apple.product-type.application"; 209 | }; 210 | E90CB4C5254B8C3F0083ECD3 /* CleanSwiftExampleTests */ = { 211 | isa = PBXNativeTarget; 212 | buildConfigurationList = E90CB4DD254B8C3F0083ECD3 /* Build configuration list for PBXNativeTarget "CleanSwiftExampleTests" */; 213 | buildPhases = ( 214 | E90CB4C2254B8C3F0083ECD3 /* Sources */, 215 | E90CB4C3254B8C3F0083ECD3 /* Frameworks */, 216 | E90CB4C4254B8C3F0083ECD3 /* Resources */, 217 | ); 218 | buildRules = ( 219 | ); 220 | dependencies = ( 221 | E90CB4C8254B8C3F0083ECD3 /* PBXTargetDependency */, 222 | ); 223 | name = CleanSwiftExampleTests; 224 | productName = CleanSwiftExampleTests; 225 | productReference = E90CB4C6254B8C3F0083ECD3 /* CleanSwiftExampleTests.xctest */; 226 | productType = "com.apple.product-type.bundle.unit-test"; 227 | }; 228 | E90CB4D0254B8C3F0083ECD3 /* CleanSwiftExampleUITests */ = { 229 | isa = PBXNativeTarget; 230 | buildConfigurationList = E90CB4E0254B8C3F0083ECD3 /* Build configuration list for PBXNativeTarget "CleanSwiftExampleUITests" */; 231 | buildPhases = ( 232 | E90CB4CD254B8C3F0083ECD3 /* Sources */, 233 | E90CB4CE254B8C3F0083ECD3 /* Frameworks */, 234 | E90CB4CF254B8C3F0083ECD3 /* Resources */, 235 | ); 236 | buildRules = ( 237 | ); 238 | dependencies = ( 239 | E90CB4D3254B8C3F0083ECD3 /* PBXTargetDependency */, 240 | ); 241 | name = CleanSwiftExampleUITests; 242 | productName = CleanSwiftExampleUITests; 243 | productReference = E90CB4D1254B8C3F0083ECD3 /* CleanSwiftExampleUITests.xctest */; 244 | productType = "com.apple.product-type.bundle.ui-testing"; 245 | }; 246 | /* End PBXNativeTarget section */ 247 | 248 | /* Begin PBXProject section */ 249 | E90CB4A8254B8C3C0083ECD3 /* Project object */ = { 250 | isa = PBXProject; 251 | attributes = { 252 | LastSwiftUpdateCheck = 1200; 253 | LastUpgradeCheck = 1200; 254 | TargetAttributes = { 255 | E90CB4AF254B8C3C0083ECD3 = { 256 | CreatedOnToolsVersion = 12.0.1; 257 | }; 258 | E90CB4C5254B8C3F0083ECD3 = { 259 | CreatedOnToolsVersion = 12.0.1; 260 | TestTargetID = E90CB4AF254B8C3C0083ECD3; 261 | }; 262 | E90CB4D0254B8C3F0083ECD3 = { 263 | CreatedOnToolsVersion = 12.0.1; 264 | TestTargetID = E90CB4AF254B8C3C0083ECD3; 265 | }; 266 | }; 267 | }; 268 | buildConfigurationList = E90CB4AB254B8C3C0083ECD3 /* Build configuration list for PBXProject "CleanSwiftExample" */; 269 | compatibilityVersion = "Xcode 9.3"; 270 | developmentRegion = en; 271 | hasScannedForEncodings = 0; 272 | knownRegions = ( 273 | en, 274 | Base, 275 | ); 276 | mainGroup = E90CB4A7254B8C3C0083ECD3; 277 | productRefGroup = E90CB4B1254B8C3C0083ECD3 /* Products */; 278 | projectDirPath = ""; 279 | projectRoot = ""; 280 | targets = ( 281 | E90CB4AF254B8C3C0083ECD3 /* CleanSwiftExample */, 282 | E90CB4C5254B8C3F0083ECD3 /* CleanSwiftExampleTests */, 283 | E90CB4D0254B8C3F0083ECD3 /* CleanSwiftExampleUITests */, 284 | ); 285 | }; 286 | /* End PBXProject section */ 287 | 288 | /* Begin PBXResourcesBuildPhase section */ 289 | E90CB4AE254B8C3C0083ECD3 /* Resources */ = { 290 | isa = PBXResourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | E94DB12B254E1AF1009215FA /* HomeViewController.storyboard in Resources */, 294 | E90CB4C0254B8C3F0083ECD3 /* LaunchScreen.storyboard in Resources */, 295 | E94DB122254E19A5009215FA /* LoginViewController.storyboard in Resources */, 296 | E90CB4BD254B8C3F0083ECD3 /* Assets.xcassets in Resources */, 297 | E90CB4BB254B8C3C0083ECD3 /* Main.storyboard in Resources */, 298 | ); 299 | runOnlyForDeploymentPostprocessing = 0; 300 | }; 301 | E90CB4C4254B8C3F0083ECD3 /* Resources */ = { 302 | isa = PBXResourcesBuildPhase; 303 | buildActionMask = 2147483647; 304 | files = ( 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | }; 308 | E90CB4CF254B8C3F0083ECD3 /* Resources */ = { 309 | isa = PBXResourcesBuildPhase; 310 | buildActionMask = 2147483647; 311 | files = ( 312 | ); 313 | runOnlyForDeploymentPostprocessing = 0; 314 | }; 315 | /* End PBXResourcesBuildPhase section */ 316 | 317 | /* Begin PBXSourcesBuildPhase section */ 318 | E90CB4AC254B8C3C0083ECD3 /* Sources */ = { 319 | isa = PBXSourcesBuildPhase; 320 | buildActionMask = 2147483647; 321 | files = ( 322 | E90CB4ED254B8C6C0083ECD3 /* LoginPresenter.swift in Sources */, 323 | E90CB4F0254B8C6C0083ECD3 /* LoginModels.swift in Sources */, 324 | E90CB4EF254B8C6C0083ECD3 /* LoginRouter.swift in Sources */, 325 | E90CB4F1254B8C6C0083ECD3 /* LoginViewController.swift in Sources */, 326 | E90CB4B8254B8C3C0083ECD3 /* ViewController.swift in Sources */, 327 | E94DB130254E1B02009215FA /* HomeViewController.swift in Sources */, 328 | E90CB4B4254B8C3C0083ECD3 /* AppDelegate.swift in Sources */, 329 | E90CB4B6254B8C3C0083ECD3 /* SceneDelegate.swift in Sources */, 330 | E94DB10B254DFAC2009215FA /* User.swift in Sources */, 331 | E90CB4F2254B8C6C0083ECD3 /* LoginInteractor.swift in Sources */, 332 | ); 333 | runOnlyForDeploymentPostprocessing = 0; 334 | }; 335 | E90CB4C2254B8C3F0083ECD3 /* Sources */ = { 336 | isa = PBXSourcesBuildPhase; 337 | buildActionMask = 2147483647; 338 | files = ( 339 | E90CB4CB254B8C3F0083ECD3 /* CleanSwiftExampleTests.swift in Sources */, 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | E90CB4CD254B8C3F0083ECD3 /* Sources */ = { 344 | isa = PBXSourcesBuildPhase; 345 | buildActionMask = 2147483647; 346 | files = ( 347 | E90CB4D6254B8C3F0083ECD3 /* CleanSwiftExampleUITests.swift in Sources */, 348 | ); 349 | runOnlyForDeploymentPostprocessing = 0; 350 | }; 351 | /* End PBXSourcesBuildPhase section */ 352 | 353 | /* Begin PBXTargetDependency section */ 354 | E90CB4C8254B8C3F0083ECD3 /* PBXTargetDependency */ = { 355 | isa = PBXTargetDependency; 356 | target = E90CB4AF254B8C3C0083ECD3 /* CleanSwiftExample */; 357 | targetProxy = E90CB4C7254B8C3F0083ECD3 /* PBXContainerItemProxy */; 358 | }; 359 | E90CB4D3254B8C3F0083ECD3 /* PBXTargetDependency */ = { 360 | isa = PBXTargetDependency; 361 | target = E90CB4AF254B8C3C0083ECD3 /* CleanSwiftExample */; 362 | targetProxy = E90CB4D2254B8C3F0083ECD3 /* PBXContainerItemProxy */; 363 | }; 364 | /* End PBXTargetDependency section */ 365 | 366 | /* Begin PBXVariantGroup section */ 367 | E90CB4B9254B8C3C0083ECD3 /* Main.storyboard */ = { 368 | isa = PBXVariantGroup; 369 | children = ( 370 | E90CB4BA254B8C3C0083ECD3 /* Base */, 371 | ); 372 | name = Main.storyboard; 373 | sourceTree = ""; 374 | }; 375 | E90CB4BE254B8C3F0083ECD3 /* LaunchScreen.storyboard */ = { 376 | isa = PBXVariantGroup; 377 | children = ( 378 | E90CB4BF254B8C3F0083ECD3 /* Base */, 379 | ); 380 | name = LaunchScreen.storyboard; 381 | sourceTree = ""; 382 | }; 383 | /* End PBXVariantGroup section */ 384 | 385 | /* Begin XCBuildConfiguration section */ 386 | E90CB4D8254B8C3F0083ECD3 /* Debug */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | ALWAYS_SEARCH_USER_PATHS = NO; 390 | CLANG_ANALYZER_NONNULL = YES; 391 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 392 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 393 | CLANG_CXX_LIBRARY = "libc++"; 394 | CLANG_ENABLE_MODULES = YES; 395 | CLANG_ENABLE_OBJC_ARC = YES; 396 | CLANG_ENABLE_OBJC_WEAK = YES; 397 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 398 | CLANG_WARN_BOOL_CONVERSION = YES; 399 | CLANG_WARN_COMMA = YES; 400 | CLANG_WARN_CONSTANT_CONVERSION = YES; 401 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 402 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 403 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 404 | CLANG_WARN_EMPTY_BODY = YES; 405 | CLANG_WARN_ENUM_CONVERSION = YES; 406 | CLANG_WARN_INFINITE_RECURSION = YES; 407 | CLANG_WARN_INT_CONVERSION = YES; 408 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 409 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 410 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 411 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 412 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 413 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 414 | CLANG_WARN_STRICT_PROTOTYPES = YES; 415 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 416 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 417 | CLANG_WARN_UNREACHABLE_CODE = YES; 418 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 419 | COPY_PHASE_STRIP = NO; 420 | DEBUG_INFORMATION_FORMAT = dwarf; 421 | ENABLE_STRICT_OBJC_MSGSEND = YES; 422 | ENABLE_TESTABILITY = YES; 423 | GCC_C_LANGUAGE_STANDARD = gnu11; 424 | GCC_DYNAMIC_NO_PIC = NO; 425 | GCC_NO_COMMON_BLOCKS = YES; 426 | GCC_OPTIMIZATION_LEVEL = 0; 427 | GCC_PREPROCESSOR_DEFINITIONS = ( 428 | "DEBUG=1", 429 | "$(inherited)", 430 | ); 431 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 432 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 433 | GCC_WARN_UNDECLARED_SELECTOR = YES; 434 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 435 | GCC_WARN_UNUSED_FUNCTION = YES; 436 | GCC_WARN_UNUSED_VARIABLE = YES; 437 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 438 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 439 | MTL_FAST_MATH = YES; 440 | ONLY_ACTIVE_ARCH = YES; 441 | SDKROOT = iphoneos; 442 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 443 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 444 | }; 445 | name = Debug; 446 | }; 447 | E90CB4D9254B8C3F0083ECD3 /* Release */ = { 448 | isa = XCBuildConfiguration; 449 | buildSettings = { 450 | ALWAYS_SEARCH_USER_PATHS = NO; 451 | CLANG_ANALYZER_NONNULL = YES; 452 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 453 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 454 | CLANG_CXX_LIBRARY = "libc++"; 455 | CLANG_ENABLE_MODULES = YES; 456 | CLANG_ENABLE_OBJC_ARC = YES; 457 | CLANG_ENABLE_OBJC_WEAK = YES; 458 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 459 | CLANG_WARN_BOOL_CONVERSION = YES; 460 | CLANG_WARN_COMMA = YES; 461 | CLANG_WARN_CONSTANT_CONVERSION = YES; 462 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 463 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 464 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 465 | CLANG_WARN_EMPTY_BODY = YES; 466 | CLANG_WARN_ENUM_CONVERSION = YES; 467 | CLANG_WARN_INFINITE_RECURSION = YES; 468 | CLANG_WARN_INT_CONVERSION = YES; 469 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 470 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 471 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 472 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 473 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 474 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 475 | CLANG_WARN_STRICT_PROTOTYPES = YES; 476 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 477 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 478 | CLANG_WARN_UNREACHABLE_CODE = YES; 479 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 480 | COPY_PHASE_STRIP = NO; 481 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 482 | ENABLE_NS_ASSERTIONS = NO; 483 | ENABLE_STRICT_OBJC_MSGSEND = YES; 484 | GCC_C_LANGUAGE_STANDARD = gnu11; 485 | GCC_NO_COMMON_BLOCKS = YES; 486 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 487 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 488 | GCC_WARN_UNDECLARED_SELECTOR = YES; 489 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 490 | GCC_WARN_UNUSED_FUNCTION = YES; 491 | GCC_WARN_UNUSED_VARIABLE = YES; 492 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 493 | MTL_ENABLE_DEBUG_INFO = NO; 494 | MTL_FAST_MATH = YES; 495 | SDKROOT = iphoneos; 496 | SWIFT_COMPILATION_MODE = wholemodule; 497 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 498 | VALIDATE_PRODUCT = YES; 499 | }; 500 | name = Release; 501 | }; 502 | E90CB4DB254B8C3F0083ECD3 /* Debug */ = { 503 | isa = XCBuildConfiguration; 504 | buildSettings = { 505 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 506 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 507 | CODE_SIGN_STYLE = Automatic; 508 | DEVELOPMENT_TEAM = MJB4D8DJZ5; 509 | INFOPLIST_FILE = CleanSwiftExample/Info.plist; 510 | LD_RUNPATH_SEARCH_PATHS = ( 511 | "$(inherited)", 512 | "@executable_path/Frameworks", 513 | ); 514 | PRODUCT_BUNDLE_IDENTIFIER = com.SweetAppsStudio.CleanSwiftExample; 515 | PRODUCT_NAME = "$(TARGET_NAME)"; 516 | SWIFT_VERSION = 5.0; 517 | TARGETED_DEVICE_FAMILY = "1,2"; 518 | }; 519 | name = Debug; 520 | }; 521 | E90CB4DC254B8C3F0083ECD3 /* Release */ = { 522 | isa = XCBuildConfiguration; 523 | buildSettings = { 524 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 525 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 526 | CODE_SIGN_STYLE = Automatic; 527 | DEVELOPMENT_TEAM = MJB4D8DJZ5; 528 | INFOPLIST_FILE = CleanSwiftExample/Info.plist; 529 | LD_RUNPATH_SEARCH_PATHS = ( 530 | "$(inherited)", 531 | "@executable_path/Frameworks", 532 | ); 533 | PRODUCT_BUNDLE_IDENTIFIER = com.SweetAppsStudio.CleanSwiftExample; 534 | PRODUCT_NAME = "$(TARGET_NAME)"; 535 | SWIFT_VERSION = 5.0; 536 | TARGETED_DEVICE_FAMILY = "1,2"; 537 | }; 538 | name = Release; 539 | }; 540 | E90CB4DE254B8C3F0083ECD3 /* Debug */ = { 541 | isa = XCBuildConfiguration; 542 | buildSettings = { 543 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 544 | BUNDLE_LOADER = "$(TEST_HOST)"; 545 | CODE_SIGN_STYLE = Automatic; 546 | DEVELOPMENT_TEAM = MJB4D8DJZ5; 547 | INFOPLIST_FILE = CleanSwiftExampleTests/Info.plist; 548 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 549 | LD_RUNPATH_SEARCH_PATHS = ( 550 | "$(inherited)", 551 | "@executable_path/Frameworks", 552 | "@loader_path/Frameworks", 553 | ); 554 | PRODUCT_BUNDLE_IDENTIFIER = com.SweetAppsStudio.CleanSwiftExampleTests; 555 | PRODUCT_NAME = "$(TARGET_NAME)"; 556 | SWIFT_VERSION = 5.0; 557 | TARGETED_DEVICE_FAMILY = "1,2"; 558 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CleanSwiftExample.app/CleanSwiftExample"; 559 | }; 560 | name = Debug; 561 | }; 562 | E90CB4DF254B8C3F0083ECD3 /* Release */ = { 563 | isa = XCBuildConfiguration; 564 | buildSettings = { 565 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 566 | BUNDLE_LOADER = "$(TEST_HOST)"; 567 | CODE_SIGN_STYLE = Automatic; 568 | DEVELOPMENT_TEAM = MJB4D8DJZ5; 569 | INFOPLIST_FILE = CleanSwiftExampleTests/Info.plist; 570 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 571 | LD_RUNPATH_SEARCH_PATHS = ( 572 | "$(inherited)", 573 | "@executable_path/Frameworks", 574 | "@loader_path/Frameworks", 575 | ); 576 | PRODUCT_BUNDLE_IDENTIFIER = com.SweetAppsStudio.CleanSwiftExampleTests; 577 | PRODUCT_NAME = "$(TARGET_NAME)"; 578 | SWIFT_VERSION = 5.0; 579 | TARGETED_DEVICE_FAMILY = "1,2"; 580 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CleanSwiftExample.app/CleanSwiftExample"; 581 | }; 582 | name = Release; 583 | }; 584 | E90CB4E1254B8C3F0083ECD3 /* Debug */ = { 585 | isa = XCBuildConfiguration; 586 | buildSettings = { 587 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 588 | CODE_SIGN_STYLE = Automatic; 589 | DEVELOPMENT_TEAM = MJB4D8DJZ5; 590 | INFOPLIST_FILE = CleanSwiftExampleUITests/Info.plist; 591 | LD_RUNPATH_SEARCH_PATHS = ( 592 | "$(inherited)", 593 | "@executable_path/Frameworks", 594 | "@loader_path/Frameworks", 595 | ); 596 | PRODUCT_BUNDLE_IDENTIFIER = com.SweetAppsStudio.CleanSwiftExampleUITests; 597 | PRODUCT_NAME = "$(TARGET_NAME)"; 598 | SWIFT_VERSION = 5.0; 599 | TARGETED_DEVICE_FAMILY = "1,2"; 600 | TEST_TARGET_NAME = CleanSwiftExample; 601 | }; 602 | name = Debug; 603 | }; 604 | E90CB4E2254B8C3F0083ECD3 /* Release */ = { 605 | isa = XCBuildConfiguration; 606 | buildSettings = { 607 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 608 | CODE_SIGN_STYLE = Automatic; 609 | DEVELOPMENT_TEAM = MJB4D8DJZ5; 610 | INFOPLIST_FILE = CleanSwiftExampleUITests/Info.plist; 611 | LD_RUNPATH_SEARCH_PATHS = ( 612 | "$(inherited)", 613 | "@executable_path/Frameworks", 614 | "@loader_path/Frameworks", 615 | ); 616 | PRODUCT_BUNDLE_IDENTIFIER = com.SweetAppsStudio.CleanSwiftExampleUITests; 617 | PRODUCT_NAME = "$(TARGET_NAME)"; 618 | SWIFT_VERSION = 5.0; 619 | TARGETED_DEVICE_FAMILY = "1,2"; 620 | TEST_TARGET_NAME = CleanSwiftExample; 621 | }; 622 | name = Release; 623 | }; 624 | /* End XCBuildConfiguration section */ 625 | 626 | /* Begin XCConfigurationList section */ 627 | E90CB4AB254B8C3C0083ECD3 /* Build configuration list for PBXProject "CleanSwiftExample" */ = { 628 | isa = XCConfigurationList; 629 | buildConfigurations = ( 630 | E90CB4D8254B8C3F0083ECD3 /* Debug */, 631 | E90CB4D9254B8C3F0083ECD3 /* Release */, 632 | ); 633 | defaultConfigurationIsVisible = 0; 634 | defaultConfigurationName = Release; 635 | }; 636 | E90CB4DA254B8C3F0083ECD3 /* Build configuration list for PBXNativeTarget "CleanSwiftExample" */ = { 637 | isa = XCConfigurationList; 638 | buildConfigurations = ( 639 | E90CB4DB254B8C3F0083ECD3 /* Debug */, 640 | E90CB4DC254B8C3F0083ECD3 /* Release */, 641 | ); 642 | defaultConfigurationIsVisible = 0; 643 | defaultConfigurationName = Release; 644 | }; 645 | E90CB4DD254B8C3F0083ECD3 /* Build configuration list for PBXNativeTarget "CleanSwiftExampleTests" */ = { 646 | isa = XCConfigurationList; 647 | buildConfigurations = ( 648 | E90CB4DE254B8C3F0083ECD3 /* Debug */, 649 | E90CB4DF254B8C3F0083ECD3 /* Release */, 650 | ); 651 | defaultConfigurationIsVisible = 0; 652 | defaultConfigurationName = Release; 653 | }; 654 | E90CB4E0254B8C3F0083ECD3 /* Build configuration list for PBXNativeTarget "CleanSwiftExampleUITests" */ = { 655 | isa = XCConfigurationList; 656 | buildConfigurations = ( 657 | E90CB4E1254B8C3F0083ECD3 /* Debug */, 658 | E90CB4E2254B8C3F0083ECD3 /* Release */, 659 | ); 660 | defaultConfigurationIsVisible = 0; 661 | defaultConfigurationName = Release; 662 | }; 663 | /* End XCConfigurationList section */ 664 | }; 665 | rootObject = E90CB4A8254B8C3C0083ECD3 /* Project object */; 666 | } 667 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample.xcodeproj/project.xcworkspace/xcuserdata/yoni.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonivav/CleanSwiftTemplates/8f18af64a0bb67f4ac2406994bd60322db7f876c/CleanSwiftExample/CleanSwiftExample.xcodeproj/project.xcworkspace/xcuserdata/yoni.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample.xcodeproj/xcuserdata/yoni.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CleanSwiftExample.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // CleanSwiftExample 4 | // 5 | // Created by Yoni Vizel on 10/30/20. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | 20 | // MARK: UISceneSession Lifecycle 21 | 22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 23 | // Called when a new scene session is being created. 24 | // Use this method to select a configuration to create the new scene with. 25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 26 | } 27 | 28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 29 | // Called when the user discards a scene session. 30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 32 | } 33 | 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Base.lproj/LaunchScreen.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 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Base.lproj/Main.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 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UIApplicationSupportsIndirectInputEvents 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UIRequiredDeviceCapabilities 49 | 50 | armv7 51 | 52 | UISupportedInterfaceOrientations 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationLandscapeLeft 56 | UIInterfaceOrientationLandscapeRight 57 | 58 | UISupportedInterfaceOrientations~ipad 59 | 60 | UIInterfaceOrientationPortrait 61 | UIInterfaceOrientationPortraitUpsideDown 62 | UIInterfaceOrientationLandscapeLeft 63 | UIInterfaceOrientationLandscapeRight 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Model/Result.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Result.swift 3 | // CleanSwiftExample 4 | // 5 | // Created by Yoni Vizel on 10/31/20. 6 | // 7 | 8 | import Foundation 9 | 10 | enum Result { 11 | case success(T) 12 | case failure(Error) 13 | } 14 | 15 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Model/User.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserModel.swift 3 | // CleanSwiftExample 4 | // 5 | // Created by Yoni Vizel on 10/31/20. 6 | // 7 | 8 | import Foundation 9 | 10 | struct User: Codable { 11 | let name: String 12 | let id: String 13 | let firstName: String 14 | let lastName: String 15 | let email: String 16 | let phone_number: String 17 | let age: Int 18 | let facebookLink: String 19 | let token: String 20 | let isInRelationship: Bool 21 | } 22 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // CleanSwiftExample 4 | // 5 | // Created by Yoni Vizel on 10/30/20. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | 15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 19 | guard let _ = (scene as? UIWindowScene) else { return } 20 | } 21 | 22 | func sceneDidDisconnect(_ scene: UIScene) { 23 | // Called as the scene is being released by the system. 24 | // This occurs shortly after the scene enters the background, or when its session is discarded. 25 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 27 | } 28 | 29 | func sceneDidBecomeActive(_ scene: UIScene) { 30 | // Called when the scene has moved from an inactive state to an active state. 31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 32 | } 33 | 34 | func sceneWillResignActive(_ scene: UIScene) { 35 | // Called when the scene will move from an active state to an inactive state. 36 | // This may occur due to temporary interruptions (ex. an incoming phone call). 37 | } 38 | 39 | func sceneWillEnterForeground(_ scene: UIScene) { 40 | // Called as the scene transitions from the background to the foreground. 41 | // Use this method to undo the changes made on entering the background. 42 | } 43 | 44 | func sceneDidEnterBackground(_ scene: UIScene) { 45 | // Called as the scene transitions from the foreground to the background. 46 | // Use this method to save data, release shared resources, and store enough scene-specific state information 47 | // to restore the scene back to its current state. 48 | } 49 | 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Screens/Home/HomeViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Screens/Home/HomeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HomeViewController.swift 3 | // CleanSwiftExample 4 | // 5 | // Created by Yoni Vizel on 11/1/20. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | class HomeViewController: UIViewController {} 12 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Screens/Login/LoginInteractor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginInteractor.swift 3 | // CleanSwiftExample 4 | // 5 | // Created by Yoni Vizel on 10/30/20. 6 | // Copyright (c) 2020 ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol LoginBusinessLogic { 16 | func login(request: Login.Login.Request) 17 | } 18 | 19 | class LoginInteractor: LoginBusinessLogic { 20 | var presenter: LoginPresentationLogic? 21 | 22 | // MARK: Login (and send response to LoginPresenter) 23 | 24 | func login(request: Login.Login.Request) { 25 | 26 | // for our example, lets build a user which this Interactor received from server 27 | let userResponse = User(name: "Capitan Jack Sparrow", 28 | id: "135735", 29 | firstName: "Jacky", 30 | lastName: "Sparrow", 31 | email: "jacky.sparrow@piratesOfTheCaribbean.com", 32 | phone_number: "+972-549-424-420", 33 | age: 31, 34 | facebookLink: "https://www.facebook.com/CaptainJackSparrow", 35 | token: "af47e509r678fuyhjv", 36 | isInRelationship: false) 37 | 38 | let response = Login.Login.Response(user: userResponse) 39 | presenter?.presentLogin(response: response) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Screens/Login/LoginModels.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginModels.swift 3 | // CleanSwiftExample 4 | // 5 | // Created by Yoni Vizel on 10/30/20. 6 | // Copyright (c) 2020 ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | enum Login 16 | { 17 | // MARK: Use cases 18 | 19 | enum Login { 20 | struct Request { 21 | let username, password: String 22 | } 23 | 24 | struct Response{ 25 | let user: User 26 | } 27 | 28 | struct ViewModelSuccess{ 29 | let username: String 30 | let age: Int 31 | } 32 | 33 | struct ViewModelFailure{ 34 | let errorMessage: String 35 | } 36 | } 37 | } 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Screens/Login/LoginPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginPresenter.swift 3 | // CleanSwiftExample 4 | // 5 | // Created by Yoni Vizel on 10/30/20. 6 | // Copyright (c) 2020 ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol LoginPresentationLogic { 16 | func presentLogin(response: Login.Login.Response) 17 | } 18 | 19 | class LoginPresenter: LoginPresentationLogic { 20 | weak var viewController: LoginDisplayLogic? 21 | 22 | // MARK: Parse and calc respnse from LoginInteractor and send simple view model to LoginViewController to be displayed 23 | 24 | func presentLogin(response: Login.Login.Response) { 25 | let username = response.user.name 26 | let age = response.user.age 27 | let viewModel = Login.Login.ViewModelSuccess(username: username, age: age) 28 | viewController?.displayUser(viewModel: viewModel) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Screens/Login/LoginRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginRouter.swift 3 | // CleanSwiftExample 4 | // 5 | // Created by Yoni Vizel on 10/30/20. 6 | // Copyright (c) 2020 ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol LoginRoutingLogic { 16 | func routeToNextScreen(segue: UIStoryboardSegue?) 17 | } 18 | 19 | class LoginRouter: NSObject, LoginRoutingLogic { 20 | weak var viewController: LoginViewController? 21 | 22 | // MARK: Routing (navigating to other screens) 23 | 24 | func routeToNextScreen(segue: UIStoryboardSegue?) { 25 | // if let segue = segue { 26 | // let destinationVC = segue.destination as! SomewhereViewController 27 | // var destinationDS = destinationVC.router!.dataStore! 28 | // passDataToSomewhere(source: dataStore!, destination: &destinationDS) 29 | // } else { 30 | // let storyboard = UIStoryboard(name: "Main", bundle: nil) 31 | // let destinationVC = storyboard.instantiateViewController(withIdentifier: "SomewhereViewController") as! SomewhereViewController 32 | // var destinationDS = destinationVC.router!.dataStore! 33 | // passDataToSomewhere(source: dataStore!, destination: &destinationDS) 34 | // navigateToSomewhere(source: viewController!, destination: destinationVC) 35 | // } 36 | } 37 | 38 | // MARK: Navigation to other screen 39 | 40 | // func navigateToSomewhere(source: LoginViewController, destination: SomewhereViewController) { 41 | // source.show(destination, sender: nil) 42 | // } 43 | 44 | // MARK: Passing data to other screen 45 | 46 | // func passDataToSomewhere(source: LoginDataStore, destination: inout SomewhereDataStore) { 47 | // destination.name = source.name 48 | // } 49 | } 50 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Screens/Login/LoginViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 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 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/Screens/Login/LoginViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginViewController.swift 3 | // CleanSwiftExample 4 | // 5 | // Created by Yoni Vizel on 10/30/20. 6 | // Copyright (c) 2020 ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so 9 | // you can apply clean architecture to your iOS and Mac projects, 10 | // see http://clean-swift.com 11 | // 12 | 13 | import UIKit 14 | 15 | protocol LoginDisplayLogic: class 16 | { 17 | func displayUser(viewModel: Login.Login.ViewModelSuccess) 18 | func displayFailure(viewModel: Login.Login.ViewModelFailure) 19 | } 20 | 21 | class LoginViewController: UIViewController, LoginDisplayLogic { 22 | 23 | private enum Segue: String { 24 | case homeSegue 25 | } 26 | 27 | var interactor: LoginBusinessLogic? 28 | var router: (NSObjectProtocol & LoginRoutingLogic)? 29 | 30 | // MARK: Object lifecycle 31 | 32 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 33 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 34 | modalPresentationStyle = .fullScreen 35 | setup() 36 | } 37 | 38 | required init?(coder aDecoder: NSCoder) { 39 | super.init(coder: aDecoder) 40 | modalPresentationStyle = .fullScreen 41 | setup() 42 | } 43 | 44 | // MARK: - Setup Clean Code Design Pattern 45 | 46 | private func setup() { 47 | let viewController = self 48 | let interactor = LoginInteractor() 49 | let presenter = LoginPresenter() 50 | let router = LoginRouter() 51 | viewController.interactor = interactor 52 | viewController.router = router 53 | interactor.presenter = presenter 54 | presenter.viewController = viewController 55 | router.viewController = viewController 56 | } 57 | 58 | //MARK: - receive events from UI 59 | 60 | @IBAction func loginButtonTapped(_ sender: Any) { 61 | login() 62 | } 63 | 64 | // MARK: - request data from LoginInteractor 65 | 66 | func login() { 67 | let request = Login.Login.Request(username: "Captain Jack Sparrow", password: "123456") 68 | interactor?.login(request: request) 69 | } 70 | 71 | // MARK: - display view model from LoginPresenter 72 | 73 | func displayUser(viewModel: Login.Login.ViewModelSuccess) { 74 | performSegue(withIdentifier: Segue.homeSegue.rawValue, sender: self) 75 | } 76 | 77 | func displayFailure(viewModel: Login.Login.ViewModelFailure) { 78 | // display error message 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // CleanSwiftExample 4 | // 5 | // Created by Yoni Vizel on 10/30/20. 6 | // 7 | 8 | import UIKit 9 | 10 | class ViewController: UIViewController { 11 | 12 | let loginViewController = LoginViewController() 13 | 14 | override func viewDidAppear(_ animated: Bool) { 15 | super.viewDidAppear(animated) 16 | 17 | guard let storyboard = storyboard else { return } 18 | 19 | let loginViewController = storyboard.instantiateViewController(identifier: "loginSegue") 20 | present(loginViewController, animated: false) 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExampleTests/CleanSwiftExampleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CleanSwiftExampleTests.swift 3 | // CleanSwiftExampleTests 4 | // 5 | // Created by Yoni Vizel on 10/30/20. 6 | // 7 | 8 | import XCTest 9 | @testable import CleanSwiftExample 10 | 11 | class CleanSwiftExampleTests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | } 16 | 17 | override func tearDownWithError() throws { 18 | // Put teardown code here. This method is called after the invocation of each test method in the class. 19 | } 20 | 21 | func testExample() throws { 22 | // This is an example of a functional test case. 23 | // Use XCTAssert and related functions to verify your tests produce the correct results. 24 | } 25 | 26 | func testPerformanceExample() throws { 27 | // This is an example of a performance test case. 28 | self.measure { 29 | // Put the code you want to measure the time of here. 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExampleUITests/CleanSwiftExampleUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CleanSwiftExampleUITests.swift 3 | // CleanSwiftExampleUITests 4 | // 5 | // Created by Yoni Vizel on 10/30/20. 6 | // 7 | 8 | import XCTest 9 | 10 | class CleanSwiftExampleUITests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | 15 | // In UI tests it is usually best to stop immediately when a failure occurs. 16 | continueAfterFailure = false 17 | 18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 19 | } 20 | 21 | override func tearDownWithError() throws { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | func testExample() throws { 26 | // UI tests must launch the application that they test. 27 | let app = XCUIApplication() 28 | app.launch() 29 | 30 | // Use recording to get started writing UI tests. 31 | // Use XCTAssert and related functions to verify your tests produce the correct results. 32 | } 33 | 34 | func testLaunchPerformance() throws { 35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 36 | // This measures how long it takes to launch your application. 37 | measure(metrics: [XCTApplicationLaunchMetric()]) { 38 | XCUIApplication().launch() 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /CleanSwiftExample/CleanSwiftExampleUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 yonivav 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 | ![logo](https://github.com/yonivav/CleanSwiftTemplates/blob/Orphan/image.png) 2 | # CleanSwiftTemplates 3 | Clean Swift (a.k.a VIP) is Uncle Bob’s Clean Architecture applied to iOS and Mac projects. In the 'Clean Swift' folder, you can find a convenience template to add a new Xcode. In 'CleanSwiftExample' you can see a basic example. 4 | 5 | # Installation 6 | 1. Download the 'Clean Swift' folder from this project 7 | 2. In Finder Mac app: open folder (⌘+⇧+G): ~/Library/Developer/Xcode/Templates/ 8 | 3. Open File Templates and paste the templates. It should look like this: 9 | ![imstructions0](https://github.com/yonivav/CleanSwiftTemplates/blob/Orphan/Instructions/instructions0.png) 10 | 4. Finish 11 | 12 | 13 | ## Example usage 14 | Lets say we want to add a login screen to our application. It will receive input from the user, which will be validated, and finally, it will display a success or failure response. 15 | For doing that please do: 16 | 1. Click on 'add new file' in Xcode, and click Next 17 | 18 | ![imstructionas1](https://github.com/yonivav/CleanSwiftTemplates/blob/Orphan/Instructions/instructions1.png) 19 | 20 | 2. In your template list go down and choose 'Scene' under the 'Clean Swift' section 21 | 22 | ![imstructionas2](https://github.com/yonivav/CleanSwiftTemplates/blob/Orphan/Instructions/instructions2.png) 23 | 24 | 3. type 'Login' for your new scene name. It should inherit from UIViewController. 25 | 26 | ![imstructionas3](https://github.com/yonivav/CleanSwiftTemplates/blob/Orphan/Instructions/instructions3.png) 27 | 28 | You should see that all 6 files were added to your project 29 | 30 | ![imstructionas4](https://github.com/yonivav/CleanSwiftTemplates/blob/Orphan/Instructions/instructions4.png) 31 | 32 | Finally, let's write some code! 33 | 34 | The flow should look like this: 35 | 1. LoginViewController needs to request an interactor to log in, with a username and password. 36 | Therefore, LoginViewInteractor should conform to a business logic protocol: 37 | ``` 38 | protocol LoginBusinessLogic { 39 | func login(request: Login.Something.Request) 40 | } 41 | ``` 42 | 2. LoginInteractor can validate this data in DB or network (NetworkWorker) and will answer it to LoginPresentor. 43 | Therefore, LoginViewPresenter should conform to a presentation logic protocol: 44 | ``` 45 | protocol LoginPresentationLogic { 46 | func presentLogin(response: Login.Login.Response) 47 | } 48 | ``` 49 | Its not too long or complicated, so LoginWorker unneeded and can be delete. 50 | 51 | 3. LoginPresneter will parse and process the response, and send to the view controller a simple straight forward data: 52 | Therefore, LoginViewController should conform to a display logic protocol: 53 | ```protocol LoginDisplayLogic: class 54 | { 55 | func displayUser(viewModel: Login.Something.ViewModeSuccess) 56 | func displayError(viewModel: Login.Something.ViewModeFailure) 57 | } 58 | ``` 59 | 60 | The model part is like that: 61 | enum Something { 62 | ``` 63 | // MARK: Use cases 64 | enum Login 65 | { 66 | // MARK: Use cases 67 | 68 | enum Login { 69 | struct Request { 70 | let username, password: String 71 | } 72 | 73 | struct Response{ 74 | let user: User 75 | } 76 | 77 | struct ViewModelSuccess{ 78 | let username: String 79 | let age: Int 80 | } 81 | 82 | struct ViewModelFailure{ 83 | let errorMessage: String 84 | } 85 | } 86 | } 87 | ``` 88 | 89 | 4. If a user log in successfully, LoginViewController will inform LoginRouter to move to another screen. 90 | Therefore, LoginRouter should conform to a routing logic protocol: 91 | ``` 92 | protocol LoginRoutingLogic { 93 | func routeToNextScreen(segue: UIStoryboardSegue?) 94 | } 95 | ``` 96 | 97 | ## Demo 98 | Open the CleanSwiftTemplatesExample project in Xcode to see the Login scenario as described in the above example. 99 | 100 | 101 | # About Clean Swift 102 | A very good explanation: 103 | 104 | https://zonneveld.dev/the-clean-swift-architecture-explained/ 105 | 106 | and also: 107 | 108 | https://clean-swift.com/clean-swift-ios-architecture/ 109 | 110 | https://sudonull.com/post/14437-Clean-swift-architecture-as-an-alternative-to-VIPER 111 | 112 | https://medium.com/dev-genius/clean-swift-vip-with-example-6f6e643a1a01 113 | 114 | 115 | In short: 116 | ### Structure 117 | The purpose of a Clean Swift design pattern is to separate the responsibilities of different entities for clarity and testability. Together, these entities form what we call scenes. Each family can operate independently using only the components within that family. 118 | The components of each family may include the following: 119 | * View Controller (with .xib or .storyboard file) 120 | * Interactor 121 | * Presenter 122 | * Model 123 | * (optional) Router 124 | * (optional) Worker 125 | 126 | ### The VIP cycle 127 | The Clean Swift architecture use a VIP cycle to help you separate logic in your application. The VIP cycle consists of a ViewController, Interactor, and a Presenter. All classes are responsible for some logic. The ViewController is responsible for the display logic, the Interactor is responsible for the business logic and the Presenter is responsible for the presentation logic. 128 | 129 | The ViewController is the first class where the action is triggered. The class is responsible for managing the views in the ViewController. In the ViewController, all outlets and IBAction functions should be listed. 130 | As soon as an action in the ViewController starts, the ViewController will pass that action to the Interactor. The Interactor is the class where all use cases should be implemented. By doing this, the Interactor is the class that contains all the business logic. This is a huge benefit when writing unit tests because when testing all interactors, all the business logic in your app is tested. 131 | The Interactor is responsible for handling the request and will return an object to the Presenter. The Presenter is the class that is responsible for presenting the object which is generated by the Interactor. The Presenter will parse that object to a ViewModel object and return an object to the ViewController to display. 132 | Using the Clean Swift architecture, you know exactly which logic should be located in which class. This makes your code more maintainable because when you need to solve a bug or want to add more functionalities, you know exactly where in your code the change should be made. 133 | 134 | ### Model 135 | During the VIP cycle, each class will add a data object when requesting an action from the other class in the cycle. When the ViewController asks the interactor to request an action from the Interactor, the ViewController will add a ‘Request’ object. This object contains all the data the interactor needs to do the business logic. 136 | The Interactor will handle the request. Once the data has been processed, it will return a ‘Response’ object to the Presenter. The Presenter will parse the data which is needed for a ‘ViewModel’ object, which will be sent to the ViewController. When the ViewModel is received by the ViewController, the ViewController only needs to update the UI elements with the data in the ViewModel. 137 | 138 | 139 | ### Router 140 | There may be situations in your app where the ViewController will present another ViewController. In Clean Swift, navigating between ViewControllers is done by a Router. 141 | If there are navigation options available for the ViewController, a Router class is added to the ViewController. The Router class contains all the navigation options where that specific ViewController can navigate through. By doing that, almost each VIP cycle will have a Router, which makes it clear what navigation options a ViewController has. 142 | A Presentor is responsible for the presentation logic. When a screen transition take place, the ViewController needs to ask this to the Interactor and then the Interactor needs to ask this to the Presentor. From there, the Presentor will decide that the ViewController may route to the next ViewController using the Router. 143 | 144 | 145 | ### Worker 146 | When having all business logic located in the Interactor, there may happen a situation where the Interactor will be a very large class. To prevent this, an Interactor can make use of multiple workers. A Worker is a helper of the Interactor, which can help receive data. 147 | A Worker is responsible for creating objects and doing network calls. Besides that, a Worker can be use to implement Third Party SDKs in your application. For example, if you use Alamofire for network requests, but do all the network requests in workers, the Alamofire SDK only needs to be imported into the worker. 148 | Workers must be generic, which means multiple interactors can use them if needed to handle data. 149 | 150 | 151 | # Contact 152 | Yoni Vizel 153 | 154 | https://github.com/yonivav 155 | 156 | 157 | # License 158 | Inspired from [this template](https://github.com/oluckyman/CleanSwift). CleanSwiftTemplates is available under the MIT license. See the LICENSE file for more info. 159 | --------------------------------------------------------------------------------