├── .gitignore ├── CHANGELOG.md ├── Clean Swift HELM ├── Configurator.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ └── ___FILEBASENAME___Configurator.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___Configurator.swift │ │ ├── ___FILEBASENAME___Interactor.swift │ │ ├── ___FILEBASENAME___Models.swift │ │ ├── ___FILEBASENAME___Presenter.swift │ │ ├── ___FILEBASENAME___Router.swift │ │ └── ___FILEBASENAME___ViewController.swift │ ├── UITableViewController │ │ ├── ___FILEBASENAME___Configurator.swift │ │ ├── ___FILEBASENAME___Interactor.swift │ │ ├── ___FILEBASENAME___Models.swift │ │ ├── ___FILEBASENAME___Presenter.swift │ │ ├── ___FILEBASENAME___Router.swift │ │ └── ___FILEBASENAME___ViewController.swift │ └── UIViewController │ │ ├── ___FILEBASENAME___Configurator.swift │ │ ├── ___FILEBASENAME___Interactor.swift │ │ ├── ___FILEBASENAME___Models.swift │ │ ├── ___FILEBASENAME___Presenter.swift │ │ ├── ___FILEBASENAME___Router.swift │ │ └── ___FILEBASENAME___ViewController.swift ├── Store.xctemplate │ ├── TemplateIcon.png │ ├── TemplateIcon@2x.png │ ├── TemplateInfo.plist │ └── ___FILEBASENAME___Store.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 ├── Example ├── .gitignore ├── Cartfile ├── Cartfile.resolved ├── Example.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Example │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── Main.storyboard │ ├── Common │ │ └── SerializableUtils.swift │ ├── Info.plist │ ├── Models │ │ ├── Name.swift │ │ └── User.swift │ ├── Scenes │ │ ├── UserDetail │ │ │ ├── UserDetailConfigurator.swift │ │ │ ├── UserDetailInteractor.swift │ │ │ ├── UserDetailModels.swift │ │ │ ├── UserDetailPresenter.swift │ │ │ ├── UserDetailRouter.swift │ │ │ ├── UserDetailViewController+TableView.swift │ │ │ └── UserDetailViewController.swift │ │ └── UserList │ │ │ ├── UI │ │ │ ├── UserTableViewCell.swift │ │ │ └── UserTableViewCell.xib │ │ │ ├── UserListConfigurator.swift │ │ │ ├── UserListInteractor.swift │ │ │ ├── UserListModels.swift │ │ │ ├── UserListPresenter.swift │ │ │ ├── UserListRouter.swift │ │ │ ├── UserListViewController+TableView.swift │ │ │ ├── UserListViewController.swift │ │ │ └── UserListWorker.swift │ └── Services │ │ ├── Mappers │ │ ├── Name+Network.swift │ │ └── User+Network.swift │ │ └── Stores │ │ ├── Definitions │ │ └── UserStore.swift │ │ └── Network │ │ ├── Router │ │ └── UserNetworkRouter.swift │ │ └── UserNetworkStore.swift └── cartupdate.sh ├── LICENSE ├── Makefile ├── README.md ├── Snippets └── clean-swift-use-case.codesnippet ├── VERSION └── configure /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | *.xcodeproj/project.xcworkspace/xcuserdata/ 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xccheckout 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # For freaks who want to look like Android Developers 49 | .idea/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | #idea for the freaks who want to look like Android developers 59 | .idea 60 | # fastlane 61 | # 62 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 63 | # screenshots whenever they are needed. 64 | # For more information about the recommended setup visit: 65 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 66 | 67 | fastlane/report.xml 68 | fastlane/screenshots 69 | .githelm 70 | .gitpublic 71 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## 1.1.2 6 | 7 | - Added @testable import to unit test files 8 | - Fixed bug to get main bundle in view controller unit test setup 9 | 10 | ## 1.1.1 11 | 12 | - Added missing router input protocol conformance to router template 13 | 14 | ## 1.1.0 15 | 16 | - Added **Unit Tests** template to generate XCTest unit test files for 17 | - View controller 18 | - Interactor 19 | - Presenter 20 | - Worker 21 | 22 | ## 1.0.0 23 | 24 | - Added the **Scene** template to generate the following Clean Swift components: 25 | - View Controller 26 | - Interactor 27 | - Presenter 28 | - Router 29 | - Worker 30 | - Models 31 | - Configurator 32 | - These components can also be generated individually. 33 | -------------------------------------------------------------------------------- /Clean Swift HELM/Configurator.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Configurator.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift HELM/Configurator.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Configurator.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift HELM/Configurator.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | MyScene 7 | Description 8 | This generates a new configurator to connect the view controller, interactor, presenter, and router. You should not need to modify it. 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___Configurator 38 | Description 39 | The configurator name 40 | Identifier 41 | configuratorName 42 | Name 43 | Configurator 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 configurator to connect the view controller, interactor, presenter, and router. You should not need to modify it. 58 | 59 | -------------------------------------------------------------------------------- /Clean Swift HELM/Configurator.xctemplate/___FILEBASENAME___Configurator.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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | // MARK: Connect View, Interactor, and Presenter 14 | 15 | extension ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___ViewControllerOutput, ___VARIABLE_sceneName___RouterDataSource, ___VARIABLE_sceneName___RouterDataDestination { 16 | } 17 | 18 | extension ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___InteractorOutput { 19 | } 20 | 21 | class ___VARIABLE_sceneName___Configurator { 22 | // MARK: Object lifecycle 23 | 24 | static let sharedInstance = ___VARIABLE_sceneName___Configurator() 25 | 26 | private init() {} 27 | 28 | // MARK: Configuration 29 | 30 | func configure(viewController: ___VARIABLE_sceneName___ViewController) { 31 | 32 | let presenter = ___VARIABLE_sceneName___Presenter() 33 | presenter.output = viewController 34 | 35 | let interactor = ___VARIABLE_sceneName___Interactor() 36 | interactor.output = presenter 37 | 38 | let router = ___VARIABLE_sceneName___Router(viewController: viewController, dataSource: interactor, dataDestination: interactor) 39 | 40 | viewController.output = interactor 41 | viewController.router = router 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Clean Swift HELM/Interactor.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Interactor.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift HELM/Interactor.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Interactor.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift HELM/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 | 7 56 | Summary 57 | This generates a new interactor using Uncle Bob's clean architecture. Your business logic goes here. 58 | 59 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | protocol ___VARIABLE_sceneName___InteractorInput { 12 | 13 | } 14 | 15 | protocol ___VARIABLE_sceneName___InteractorOutput { 16 | 17 | } 18 | 19 | protocol ___VARIABLE_sceneName___DataSource { 20 | 21 | } 22 | 23 | protocol ___VARIABLE_sceneName___DataDestination { 24 | 25 | } 26 | 27 | class ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___InteractorInput, ___VARIABLE_sceneName___DataSource, ___VARIABLE_sceneName___DataDestination { 28 | 29 | var output: ___VARIABLE_sceneName___InteractorOutput? 30 | 31 | // MARK: Business logic 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Clean Swift HELM/Models.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Models.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift HELM/Models.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Models.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift HELM/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 | 3 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 HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | // 11 | // Type "usecase" for some magic! 12 | 13 | struct ___VARIABLE_sceneName___Scene { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Clean Swift HELM/Presenter.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Presenter.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift HELM/Presenter.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Presenter.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift HELM/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 | 6 56 | Summary 57 | This generates a new presenter using Uncle Bob's clean architecture. Your presentation logic goes here. 58 | 59 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | protocol ___VARIABLE_sceneName___PresenterInput { 12 | 13 | } 14 | 15 | protocol ___VARIABLE_sceneName___PresenterOutput: class { 16 | 17 | } 18 | 19 | class ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___PresenterInput { 20 | 21 | weak var output: ___VARIABLE_sceneName___PresenterOutput? 22 | 23 | // MARK: Presentation logic 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Clean Swift HELM/Router.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Router.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift HELM/Router.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Router.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift HELM/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 | 5 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 HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | protocol ___VARIABLE_sceneName___RouterInput { 14 | 15 | } 16 | 17 | protocol ___VARIABLE_sceneName___RouterDataSource: class { 18 | 19 | } 20 | 21 | protocol ___VARIABLE_sceneName___RouterDataDestination: class { 22 | 23 | } 24 | 25 | class ___VARIABLE_sceneName___Router: ___VARIABLE_sceneName___RouterInput { 26 | 27 | weak var viewController: ___VARIABLE_sceneName___ViewController! 28 | weak private var dataSource: ___VARIABLE_sceneName___RouterDataSource! 29 | weak var dataDestination: ___VARIABLE_sceneName___RouterDataDestination! 30 | 31 | init(viewController: ___VARIABLE_sceneName___ViewController, dataSource: ___VARIABLE_sceneName___RouterDataSource, dataDestination: ___VARIABLE_sceneName___RouterDataDestination) { 32 | self.viewController = viewController 33 | self.dataSource = dataSource 34 | self.dataDestination = dataDestination 35 | } 36 | 37 | // MARK: Navigation 38 | 39 | // MARK: Communication 40 | 41 | func passDataToNextScene(for segue: UIStoryboardSegue) { 42 | // NOTE: Teach the router which scenes it can communicate with 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Clean Swift HELM/Scene.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Scene.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift HELM/Scene.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Scene.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift HELM/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___Models 108 | Description 109 | The model file name 110 | Identifier 111 | modelFileName 112 | Name 113 | Model File Name: 114 | Required 115 | 116 | Type 117 | static 118 | 119 | 120 | Default 121 | UIViewController 122 | Description 123 | What view controller class to subclass for the new scene 124 | FallbackHeader 125 | #import <UIKit/UIKit.h> 126 | Identifier 127 | viewControllerSubclass 128 | Name 129 | Subclass of: 130 | NotPersisted 131 | 132 | Required 133 | YES 134 | Type 135 | class 136 | Values 137 | 138 | UIViewController 139 | UITableViewController 140 | UICollectionViewController 141 | 142 | 143 | 144 | Platforms 145 | 146 | com.apple.platform.iphoneos 147 | 148 | SortOrder 149 | 9 150 | Summary 151 | This generates a new scene using Uncle Bob's clean architecture. 152 | 153 | 154 | -------------------------------------------------------------------------------- /Clean Swift HELM/Scene.xctemplate/UICollectionViewController/___FILEBASENAME___Configurator.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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | // MARK: Connect View, Interactor, and Presenter 14 | 15 | extension ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___ViewControllerOutput, ___VARIABLE_sceneName___RouterDataSource, ___VARIABLE_sceneName___RouterDataDestination { 16 | } 17 | 18 | extension ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___InteractorOutput { 19 | } 20 | 21 | class ___VARIABLE_sceneName___Configurator { 22 | // MARK: Object lifecycle 23 | 24 | static let sharedInstance = ___VARIABLE_sceneName___Configurator() 25 | 26 | private init() {} 27 | 28 | // MARK: Configuration 29 | 30 | func configure(viewController: ___VARIABLE_sceneName___ViewController) { 31 | 32 | let presenter = ___VARIABLE_sceneName___Presenter() 33 | presenter.output = viewController 34 | 35 | let interactor = ___VARIABLE_sceneName___Interactor() 36 | interactor.output = presenter 37 | 38 | let router = ___VARIABLE_sceneName___Router(viewController: viewController, dataSource: interactor, dataDestination: interactor) 39 | 40 | viewController.output = interactor 41 | viewController.router = router 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | protocol ___VARIABLE_sceneName___InteractorInput { 12 | 13 | } 14 | 15 | protocol ___VARIABLE_sceneName___InteractorOutput { 16 | 17 | } 18 | 19 | protocol ___VARIABLE_sceneName___DataSource { 20 | 21 | } 22 | 23 | protocol ___VARIABLE_sceneName___DataDestination { 24 | 25 | } 26 | 27 | class ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___InteractorInput, ___VARIABLE_sceneName___DataSource, ___VARIABLE_sceneName___DataDestination { 28 | 29 | var output: ___VARIABLE_sceneName___InteractorOutput? 30 | 31 | // MARK: Business logic 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | // 11 | // Type "usecase" for some magic! 12 | 13 | struct ___VARIABLE_sceneName___Scene { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | protocol ___VARIABLE_sceneName___PresenterInput { 12 | 13 | } 14 | 15 | protocol ___VARIABLE_sceneName___PresenterOutput: class { 16 | 17 | } 18 | 19 | class ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___PresenterInput { 20 | 21 | weak var output: ___VARIABLE_sceneName___PresenterOutput? 22 | 23 | // MARK: Presentation logic 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | protocol ___VARIABLE_sceneName___RouterInput { 14 | 15 | } 16 | 17 | protocol ___VARIABLE_sceneName___RouterDataSource: class { 18 | 19 | } 20 | 21 | protocol ___VARIABLE_sceneName___RouterDataDestination: class { 22 | 23 | } 24 | 25 | class ___VARIABLE_sceneName___Router: ___VARIABLE_sceneName___RouterInput { 26 | 27 | weak var viewController: ___VARIABLE_sceneName___ViewController! 28 | weak private var dataSource: ___VARIABLE_sceneName___RouterDataSource! 29 | weak var dataDestination: ___VARIABLE_sceneName___RouterDataDestination! 30 | 31 | init(viewController: ___VARIABLE_sceneName___ViewController, dataSource: ___VARIABLE_sceneName___RouterDataSource, dataDestination: ___VARIABLE_sceneName___RouterDataDestination) { 32 | self.viewController = viewController 33 | self.dataSource = dataSource 34 | self.dataDestination = dataDestination 35 | } 36 | 37 | // MARK: Navigation 38 | 39 | // MARK: Communication 40 | 41 | func passDataToNextScene(for segue: UIStoryboardSegue) { 42 | // NOTE: Teach the router which scenes it can communicate with 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | protocol ___VARIABLE_sceneName___ViewControllerInput { 14 | 15 | } 16 | 17 | protocol ___VARIABLE_sceneName___ViewControllerOutput { 18 | 19 | } 20 | 21 | class ___VARIABLE_sceneName___ViewController: UICollectionViewController, ___VARIABLE_sceneName___ViewControllerInput { 22 | 23 | var output: ___VARIABLE_sceneName___ViewControllerOutput? 24 | var router: ___VARIABLE_sceneName___Router? 25 | 26 | // MARK: Object lifecycle 27 | 28 | override func awakeFromNib() { 29 | super.awakeFromNib() 30 | ___VARIABLE_sceneName___Configurator.sharedInstance.configure(viewController: self) 31 | } 32 | 33 | // MARK: View lifecycle 34 | 35 | override func viewDidLoad() { 36 | super.viewDidLoad() 37 | } 38 | 39 | // MARK: Requests 40 | 41 | 42 | // MARK: Display logic 43 | 44 | } 45 | 46 | //This should be on configurator but for some reason storyboard doesn't detect ViewController's name if placed there 47 | extension ___VARIABLE_sceneName___ViewController: ___VARIABLE_sceneName___PresenterOutput { 48 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 49 | router?.passDataToNextScene(for: segue) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Clean Swift HELM/Scene.xctemplate/UITableViewController/___FILEBASENAME___Configurator.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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | // MARK: Connect View, Interactor, and Presenter 14 | 15 | extension ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___ViewControllerOutput, ___VARIABLE_sceneName___RouterDataSource, ___VARIABLE_sceneName___RouterDataDestination { 16 | } 17 | 18 | extension ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___InteractorOutput { 19 | } 20 | 21 | class ___VARIABLE_sceneName___Configurator { 22 | // MARK: Object lifecycle 23 | 24 | static let sharedInstance = ___VARIABLE_sceneName___Configurator() 25 | 26 | private init() {} 27 | 28 | // MARK: Configuration 29 | 30 | func configure(viewController: ___VARIABLE_sceneName___ViewController) { 31 | 32 | let presenter = ___VARIABLE_sceneName___Presenter() 33 | presenter.output = viewController 34 | 35 | let interactor = ___VARIABLE_sceneName___Interactor() 36 | interactor.output = presenter 37 | 38 | let router = ___VARIABLE_sceneName___Router(viewController: viewController, dataSource: interactor, dataDestination: interactor) 39 | 40 | viewController.output = interactor 41 | viewController.router = router 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | protocol ___VARIABLE_sceneName___InteractorInput { 12 | 13 | } 14 | 15 | protocol ___VARIABLE_sceneName___InteractorOutput { 16 | 17 | } 18 | 19 | protocol ___VARIABLE_sceneName___DataSource { 20 | 21 | } 22 | 23 | protocol ___VARIABLE_sceneName___DataDestination { 24 | 25 | } 26 | 27 | class ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___InteractorInput, ___VARIABLE_sceneName___DataSource, ___VARIABLE_sceneName___DataDestination { 28 | 29 | var output: ___VARIABLE_sceneName___InteractorOutput? 30 | 31 | // MARK: Business logic 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | // 11 | // Type "usecase" for some magic! 12 | 13 | struct ___VARIABLE_sceneName___Scene { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | protocol ___VARIABLE_sceneName___PresenterInput { 12 | 13 | } 14 | 15 | protocol ___VARIABLE_sceneName___PresenterOutput: class { 16 | 17 | } 18 | 19 | class ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___PresenterInput { 20 | 21 | weak var output: ___VARIABLE_sceneName___PresenterOutput? 22 | 23 | // MARK: Presentation logic 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | protocol ___VARIABLE_sceneName___RouterInput { 14 | 15 | } 16 | 17 | protocol ___VARIABLE_sceneName___RouterDataSource: class { 18 | 19 | } 20 | 21 | protocol ___VARIABLE_sceneName___RouterDataDestination: class { 22 | 23 | } 24 | 25 | class ___VARIABLE_sceneName___Router: ___VARIABLE_sceneName___RouterInput { 26 | 27 | weak var viewController: ___VARIABLE_sceneName___ViewController! 28 | weak private var dataSource: ___VARIABLE_sceneName___RouterDataSource! 29 | weak var dataDestination: ___VARIABLE_sceneName___RouterDataDestination! 30 | 31 | init(viewController: ___VARIABLE_sceneName___ViewController, dataSource: ___VARIABLE_sceneName___RouterDataSource, dataDestination: ___VARIABLE_sceneName___RouterDataDestination) { 32 | self.viewController = viewController 33 | self.dataSource = dataSource 34 | self.dataDestination = dataDestination 35 | } 36 | 37 | // MARK: Navigation 38 | 39 | // MARK: Communication 40 | 41 | func passDataToNextScene(for segue: UIStoryboardSegue) { 42 | // NOTE: Teach the router which scenes it can communicate with 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | protocol ___VARIABLE_sceneName___ViewControllerInput { 14 | 15 | } 16 | 17 | protocol ___VARIABLE_sceneName___ViewControllerOutput { 18 | 19 | } 20 | 21 | class ___VARIABLE_sceneName___ViewController: UITableViewController, ___VARIABLE_sceneName___ViewControllerInput { 22 | 23 | var output: ___VARIABLE_sceneName___ViewControllerOutput? 24 | var router: ___VARIABLE_sceneName___Router? 25 | 26 | // MARK: Object lifecycle 27 | 28 | override func awakeFromNib() { 29 | super.awakeFromNib() 30 | ___VARIABLE_sceneName___Configurator.sharedInstance.configure(viewController: self) 31 | } 32 | 33 | // MARK: View lifecycle 34 | 35 | override func viewDidLoad() { 36 | super.viewDidLoad() 37 | } 38 | 39 | // MARK: Requests 40 | 41 | 42 | // MARK: Display logic 43 | 44 | } 45 | 46 | //This should be on configurator but for some reason storyboard doesn't detect ViewController's name if placed there 47 | extension ___VARIABLE_sceneName___ViewController: ___VARIABLE_sceneName___PresenterOutput { 48 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 49 | router?.passDataToNextScene(for: segue) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Clean Swift HELM/Scene.xctemplate/UIViewController/___FILEBASENAME___Configurator.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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | // MARK: Connect View, Interactor, and Presenter 14 | 15 | extension ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___ViewControllerOutput, ___VARIABLE_sceneName___RouterDataSource, ___VARIABLE_sceneName___RouterDataDestination { 16 | } 17 | 18 | extension ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___InteractorOutput { 19 | } 20 | 21 | class ___VARIABLE_sceneName___Configurator { 22 | // MARK: Object lifecycle 23 | 24 | static let sharedInstance = ___VARIABLE_sceneName___Configurator() 25 | 26 | private init() {} 27 | 28 | // MARK: Configuration 29 | 30 | func configure(viewController: ___VARIABLE_sceneName___ViewController) { 31 | 32 | let presenter = ___VARIABLE_sceneName___Presenter() 33 | presenter.output = viewController 34 | 35 | let interactor = ___VARIABLE_sceneName___Interactor() 36 | interactor.output = presenter 37 | 38 | let router = ___VARIABLE_sceneName___Router(viewController: viewController, dataSource: interactor, dataDestination: interactor) 39 | 40 | viewController.output = interactor 41 | viewController.router = router 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | protocol ___VARIABLE_sceneName___InteractorInput { 12 | 13 | } 14 | 15 | protocol ___VARIABLE_sceneName___InteractorOutput { 16 | 17 | } 18 | 19 | protocol ___VARIABLE_sceneName___DataSource { 20 | 21 | } 22 | 23 | protocol ___VARIABLE_sceneName___DataDestination { 24 | 25 | } 26 | 27 | class ___VARIABLE_sceneName___Interactor: ___VARIABLE_sceneName___InteractorInput, ___VARIABLE_sceneName___DataSource, ___VARIABLE_sceneName___DataDestination { 28 | 29 | var output: ___VARIABLE_sceneName___InteractorOutput? 30 | 31 | // MARK: Business logic 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | // 11 | // Type "usecase" for some magic! 12 | 13 | struct ___VARIABLE_sceneName___Scene { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | protocol ___VARIABLE_sceneName___PresenterInput { 12 | 13 | } 14 | 15 | protocol ___VARIABLE_sceneName___PresenterOutput: class { 16 | 17 | } 18 | 19 | class ___VARIABLE_sceneName___Presenter: ___VARIABLE_sceneName___PresenterInput { 20 | 21 | weak var output: ___VARIABLE_sceneName___PresenterOutput? 22 | 23 | // MARK: Presentation logic 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | protocol ___VARIABLE_sceneName___RouterInput { 14 | 15 | } 16 | 17 | protocol ___VARIABLE_sceneName___RouterDataSource: class { 18 | 19 | } 20 | 21 | protocol ___VARIABLE_sceneName___RouterDataDestination: class { 22 | 23 | } 24 | 25 | class ___VARIABLE_sceneName___Router: ___VARIABLE_sceneName___RouterInput { 26 | 27 | weak var viewController: ___VARIABLE_sceneName___ViewController! 28 | weak private var dataSource: ___VARIABLE_sceneName___RouterDataSource! 29 | weak var dataDestination: ___VARIABLE_sceneName___RouterDataDestination! 30 | 31 | init(viewController: ___VARIABLE_sceneName___ViewController, dataSource: ___VARIABLE_sceneName___RouterDataSource, dataDestination: ___VARIABLE_sceneName___RouterDataDestination) { 32 | self.viewController = viewController 33 | self.dataSource = dataSource 34 | self.dataDestination = dataDestination 35 | } 36 | 37 | // MARK: Navigation 38 | 39 | // MARK: Communication 40 | 41 | func passDataToNextScene(for segue: UIStoryboardSegue) { 42 | // NOTE: Teach the router which scenes it can communicate with 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | protocol ___VARIABLE_sceneName___ViewControllerInput { 14 | 15 | } 16 | 17 | protocol ___VARIABLE_sceneName___ViewControllerOutput { 18 | 19 | } 20 | 21 | class ___VARIABLE_sceneName___ViewController: UIViewController, ___VARIABLE_sceneName___ViewControllerInput { 22 | 23 | var output: ___VARIABLE_sceneName___ViewControllerOutput? 24 | var router: ___VARIABLE_sceneName___Router? 25 | 26 | // MARK: Object lifecycle 27 | 28 | override func awakeFromNib() { 29 | super.awakeFromNib() 30 | ___VARIABLE_sceneName___Configurator.sharedInstance.configure(viewController: self) 31 | } 32 | 33 | // MARK: View lifecycle 34 | 35 | override func viewDidLoad() { 36 | super.viewDidLoad() 37 | } 38 | 39 | // MARK: Requests 40 | 41 | 42 | // MARK: Display logic 43 | 44 | } 45 | 46 | //This should be on configurator but for some reason storyboard doesn't detect ViewController's name if placed there 47 | extension ___VARIABLE_sceneName___ViewController: ___VARIABLE_sceneName___PresenterOutput { 48 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 49 | router?.passDataToNextScene(for: segue) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Clean Swift HELM/Store.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Store.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift HELM/Store.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Store.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift HELM/Store.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | MyStore 7 | Description 8 | This generates a new Store protocol to access specific entities with CRUD methods. 9 | Kind 10 | Xcode.IDEKit.TextSubstitutionFileTemplateKind 11 | Options 12 | 13 | 14 | Description 15 | The name of the entity to create the store 16 | Identifier 17 | entityName 18 | Name 19 | Entity Name: 20 | NotPersisted 21 | 22 | Required 23 | 24 | Type 25 | text 26 | 27 | 28 | Description 29 | The plural name of the entity to create the store 30 | Identifier 31 | entityPluralName 32 | Name 33 | Plural Name: 34 | Required 35 | 36 | NotPersisted 37 | 38 | Type 39 | text 40 | 41 | 42 | Description 43 | The lowercase name of the entity to create the store 44 | Identifier 45 | entityLowercaseName 46 | Name 47 | Lowercase Name: 48 | Required 49 | 50 | NotPersisted 51 | 52 | Type 53 | text 54 | 55 | 56 | Default 57 | ___VARIABLE_entityName___ 58 | Identifier 59 | productName 60 | Type 61 | static 62 | 63 | 64 | Default 65 | ___VARIABLE_entityName:identifier___Store 66 | Description 67 | The store name 68 | Identifier 69 | storeName 70 | Name 71 | Store Name: 72 | Required 73 | 74 | Type 75 | static 76 | 77 | 78 | Platforms 79 | 80 | com.apple.platform.iphoneos 81 | 82 | SortOrder 83 | 2 84 | Summary 85 | This generates a new Store protocol to access specific entities with CRUD methods. 86 | 87 | 88 | -------------------------------------------------------------------------------- /Clean Swift HELM/Store.xctemplate/___FILEBASENAME___Store.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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | protocol ___VARIABLE_entityName___Store { 12 | func get___VARIABLE_entityPluralName___(completion: @escaping ___VARIABLE_entityName___StoreGet___VARIABLE_entityPluralName___CompletionHandler) 13 | func get___VARIABLE_entityName___(withId id: String, completion: @escaping ___VARIABLE_entityName___StoreGet___VARIABLE_entityName___CompletionHandler) 14 | func create___VARIABLE_entityName___(___VARIABLE_entityLowercaseName___ToCreate ___VARIABLE_entityLowercaseName___: ___VARIABLE_entityName___, completion: @escaping ___VARIABLE_entityName___StoreCreate___VARIABLE_entityName___CompletionHandler) 15 | func update___VARIABLE_entityName___(___VARIABLE_entityLowercaseName___ToUpdate ___VARIABLE_entityLowercaseName___: ___VARIABLE_entityName___, completion: @escaping ___VARIABLE_entityName___StoreUpdate___VARIABLE_entityName___CompletionHandler) 16 | func delete___VARIABLE_entityName___(withId id: String, completion: @escaping ___VARIABLE_entityName___StoreDelete___VARIABLE_entityName___CompletionHandler) 17 | } 18 | 19 | typealias ___VARIABLE_entityName___StoreGet___VARIABLE_entityPluralName___CompletionHandler = (___VARIABLE_entityName___StoreResult<[___VARIABLE_entityName___]>) -> Void 20 | typealias ___VARIABLE_entityName___StoreGet___VARIABLE_entityName___CompletionHandler = (___VARIABLE_entityName___StoreResult<___VARIABLE_entityName___>) -> Void 21 | typealias ___VARIABLE_entityName___StoreCreate___VARIABLE_entityName___CompletionHandler = (___VARIABLE_entityName___StoreEmptyResult) -> Void 22 | typealias ___VARIABLE_entityName___StoreUpdate___VARIABLE_entityName___CompletionHandler = (___VARIABLE_entityName___StoreEmptyResult) -> Void 23 | typealias ___VARIABLE_entityName___StoreDelete___VARIABLE_entityName___CompletionHandler = (___VARIABLE_entityName___StoreEmptyResult) -> Void 24 | 25 | enum ___VARIABLE_entityName___StoreResult { 26 | case success(result: U) 27 | case failure(error: ___VARIABLE_entityName___StoreError) 28 | } 29 | 30 | enum ___VARIABLE_entityName___StoreEmptyResult { 31 | case success 32 | case failure(error: ___VARIABLE_entityName___StoreError) 33 | } 34 | 35 | enum ___VARIABLE_entityName___StoreError: Equatable, Error { 36 | case cannotGet(String) 37 | case cannotCreate(String) 38 | case cannotUpdate(String) 39 | case cannotDelete(String) 40 | } 41 | 42 | func ==(lhs: ___VARIABLE_entityName___StoreError, rhs: ___VARIABLE_entityName___StoreError) -> Bool { 43 | switch (lhs, rhs) { 44 | case (.cannotGet(let a), .cannotGet(let b)) where a == b: return true 45 | case (.cannotCreate(let a), .cannotCreate(let b)) where a == b: return true 46 | case (.cannotUpdate(let a), .cannotUpdate(let b)) where a == b: return true 47 | case (.cannotDelete(let a), .cannotDelete(let b)) where a == b: return true 48 | default: 49 | return false 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Clean Swift HELM/Unit Tests.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Unit Tests.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift HELM/Unit Tests.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Unit Tests.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift HELM/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 | Platforms 79 | 80 | com.apple.platform.iphoneos 81 | 82 | SortOrder 83 | 1 84 | Summary 85 | This generates unit tests for your scene using Uncle Bob's clean architecture. 86 | 87 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | @testable import ___PROJECTNAME___ 13 | import XCTest 14 | 15 | class ___FILEBASENAMEASIDENTIFIER___InteractorTests: XCTestCase { 16 | // MARK: Subject under test 17 | 18 | var sut: ___FILEBASENAMEASIDENTIFIER___Interactor! 19 | 20 | // MARK: Test lifecycle 21 | 22 | override func setUp() { 23 | super.setUp() 24 | setup___FILEBASENAMEASIDENTIFIER___Interactor() 25 | } 26 | 27 | override func tearDown() { 28 | super.tearDown() 29 | } 30 | 31 | // MARK: Test setup 32 | 33 | func setup___FILEBASENAMEASIDENTIFIER___Interactor() { 34 | sut = ___FILEBASENAMEASIDENTIFIER___Interactor() 35 | } 36 | 37 | // MARK: Test doubles 38 | 39 | // MARK: Tests 40 | 41 | func testSomething() { 42 | // Given 43 | 44 | // When 45 | 46 | // Then 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | @testable import ___PROJECTNAME___ 13 | import XCTest 14 | 15 | class ___FILEBASENAMEASIDENTIFIER___PresenterTests: XCTestCase { 16 | // MARK: Subject under test 17 | 18 | var sut: ___FILEBASENAMEASIDENTIFIER___Presenter! 19 | 20 | // MARK: Test lifecycle 21 | 22 | override func setUp() { 23 | super.setUp() 24 | setup___FILEBASENAMEASIDENTIFIER___Presenter() 25 | } 26 | 27 | override func tearDown() { 28 | super.tearDown() 29 | } 30 | 31 | // MARK: Test setup 32 | 33 | func setup___FILEBASENAMEASIDENTIFIER___Presenter() { 34 | sut = ___FILEBASENAMEASIDENTIFIER___Presenter() 35 | } 36 | 37 | // MARK: Test doubles 38 | 39 | // MARK: Tests 40 | 41 | func testSomething() { 42 | // Given 43 | 44 | // When 45 | 46 | // Then 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | @testable import ___PROJECTNAME___ 13 | import XCTest 14 | 15 | class ___FILEBASENAMEASIDENTIFIER___ViewControllerTests: XCTestCase { 16 | // MARK: Subject under test 17 | 18 | var sut: ___FILEBASENAMEASIDENTIFIER___ViewController! 19 | var window: UIWindow! 20 | 21 | // MARK: Test lifecycle 22 | 23 | override func setUp() { 24 | super.setUp() 25 | window = UIWindow() 26 | setup___FILEBASENAMEASIDENTIFIER___ViewController() 27 | } 28 | 29 | override func tearDown() { 30 | window = nil 31 | super.tearDown() 32 | } 33 | 34 | // MARK: Test setup 35 | 36 | func setup___FILEBASENAMEASIDENTIFIER___ViewController() { 37 | let bundle = Bundle.main 38 | let storyboard = UIStoryboard(name: "Main", bundle: bundle) 39 | sut = storyboard.instantiateViewController(withIdentifier: "___FILEBASENAMEASIDENTIFIER___ViewController") as! ___FILEBASENAMEASIDENTIFIER___ViewController 40 | } 41 | 42 | func loadView() { 43 | window.addSubview(sut.view) 44 | RunLoop.current.run(until: Date()) 45 | } 46 | 47 | // MARK: Test doubles 48 | 49 | // MARK: Tests 50 | 51 | func testSomething() { 52 | // Given 53 | 54 | // When 55 | 56 | // Then 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | @testable import ___PROJECTNAME___ 13 | import XCTest 14 | 15 | class ___FILEBASENAMEASIDENTIFIER___WorkerTests: XCTestCase { 16 | // MARK: Subject under test 17 | 18 | var sut: ___FILEBASENAMEASIDENTIFIER___Worker! 19 | 20 | // MARK: Test lifecycle 21 | 22 | override func setUp() { 23 | super.setUp() 24 | setup___FILEBASENAMEASIDENTIFIER___Worker() 25 | } 26 | 27 | override func tearDown() { 28 | super.tearDown() 29 | } 30 | 31 | // MARK: Test setup 32 | 33 | func setup___FILEBASENAMEASIDENTIFIER___Worker() { 34 | sut = ___FILEBASENAMEASIDENTIFIER___Worker() 35 | } 36 | 37 | // MARK: Test doubles 38 | 39 | // MARK: Tests 40 | 41 | func testSomething() { 42 | // Given 43 | 44 | // When 45 | 46 | // Then 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Clean Swift HELM/View Controller.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/View Controller.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift HELM/View Controller.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/View Controller.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift HELM/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 | 8 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 HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | protocol ___VARIABLE_sceneName___ViewControllerInput { 14 | 15 | } 16 | 17 | protocol ___VARIABLE_sceneName___ViewControllerOutput { 18 | 19 | } 20 | 21 | class ___VARIABLE_sceneName___ViewController: UICollectionViewController, ___VARIABLE_sceneName___ViewControllerInput { 22 | 23 | var output: ___VARIABLE_sceneName___ViewControllerOutput? 24 | var router: ___VARIABLE_sceneName___Router? 25 | 26 | // MARK: Object lifecycle 27 | 28 | override func awakeFromNib() { 29 | super.awakeFromNib() 30 | ___VARIABLE_sceneName___Configurator.sharedInstance.configure(viewController: self) 31 | } 32 | 33 | // MARK: View lifecycle 34 | 35 | override func viewDidLoad() { 36 | super.viewDidLoad() 37 | } 38 | 39 | // MARK: Requests 40 | 41 | 42 | // MARK: Display logic 43 | 44 | } 45 | 46 | //This should be on configurator but for some reason storyboard doesn't detect ViewController's name if placed there 47 | extension ___VARIABLE_sceneName___ViewController: ___VARIABLE_sceneName___PresenterOutput { 48 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 49 | router?.passDataToNextScene(for: segue) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | protocol ___VARIABLE_sceneName___ViewControllerInput { 14 | 15 | } 16 | 17 | protocol ___VARIABLE_sceneName___ViewControllerOutput { 18 | 19 | } 20 | 21 | class ___VARIABLE_sceneName___ViewController: UITableViewController, ___VARIABLE_sceneName___ViewControllerInput { 22 | 23 | var output: ___VARIABLE_sceneName___ViewControllerOutput? 24 | var router: ___VARIABLE_sceneName___Router? 25 | 26 | // MARK: Object lifecycle 27 | 28 | override func awakeFromNib() { 29 | super.awakeFromNib() 30 | ___VARIABLE_sceneName___Configurator.sharedInstance.configure(viewController: self) 31 | } 32 | 33 | // MARK: View lifecycle 34 | 35 | override func viewDidLoad() { 36 | super.viewDidLoad() 37 | } 38 | 39 | // MARK: Requests 40 | 41 | 42 | // MARK: Display logic 43 | 44 | } 45 | 46 | //This should be on configurator but for some reason storyboard doesn't detect ViewController's name if placed there 47 | extension ___VARIABLE_sceneName___ViewController: ___VARIABLE_sceneName___PresenterOutput { 48 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 49 | router?.passDataToNextScene(for: segue) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | import UIKit 12 | 13 | protocol ___VARIABLE_sceneName___ViewControllerInput { 14 | 15 | } 16 | 17 | protocol ___VARIABLE_sceneName___ViewControllerOutput { 18 | 19 | } 20 | 21 | class ___VARIABLE_sceneName___ViewController: UIViewController, ___VARIABLE_sceneName___ViewControllerInput { 22 | 23 | var output: ___VARIABLE_sceneName___ViewControllerOutput? 24 | var router: ___VARIABLE_sceneName___Router? 25 | 26 | // MARK: Object lifecycle 27 | 28 | override func awakeFromNib() { 29 | super.awakeFromNib() 30 | ___VARIABLE_sceneName___Configurator.sharedInstance.configure(viewController: self) 31 | } 32 | 33 | // MARK: View lifecycle 34 | 35 | override func viewDidLoad() { 36 | super.viewDidLoad() 37 | } 38 | 39 | // MARK: Requests 40 | 41 | 42 | // MARK: Display logic 43 | 44 | } 45 | 46 | //This should be on configurator but for some reason storyboard doesn't detect ViewController's name if placed there 47 | extension ___VARIABLE_sceneName___ViewController: ___VARIABLE_sceneName___PresenterOutput { 48 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 49 | router?.passDataToNextScene(for: segue) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Clean Swift HELM/Worker.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Worker.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /Clean Swift HELM/Worker.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelmMobile/clean-swift-templates/8a324044926dd98c37317683b82a2672a4cfccef/Clean Swift HELM/Worker.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /Clean Swift HELM/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 | 4 56 | Summary 57 | This generates a new worker to perform your specific business logic. 58 | 59 | -------------------------------------------------------------------------------- /Clean Swift HELM/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 HELM Xcode Templates 9 | // https://github.com/HelmMobile/clean-swift-templates 10 | 11 | class ___FILEBASENAMEASIDENTIFIER___Worker { 12 | // MARK: Business Logic 13 | 14 | func doSomeWork() { 15 | // NOTE: Do the work 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /Example/Cartfile: -------------------------------------------------------------------------------- 1 | 2 | 3 | github "onevcat/Kingfisher" ~> 3.6 4 | github "Alamofire/Alamofire" ~> 4.4 5 | github "SwiftyJSON/SwiftyJSON" ~> 3.1.4 6 | -------------------------------------------------------------------------------- /Example/Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "Alamofire/Alamofire" "4.4.0" 2 | github "SwiftyJSON/SwiftyJSON" "3.1.4" 3 | github "onevcat/Kingfisher" "3.6.1" 4 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5D3865A41E962BCF00CFEDD1 /* UserDetailViewController+TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D3865A31E962BCF00CFEDD1 /* UserDetailViewController+TableView.swift */; }; 11 | 5D3865A71E962DA400CFEDD1 /* UserTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D3865A51E962DA400CFEDD1 /* UserTableViewCell.swift */; }; 12 | 5D3865A81E962DA400CFEDD1 /* UserTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5D3865A61E962DA400CFEDD1 /* UserTableViewCell.xib */; }; 13 | 5DB2FAC81E94FBE200B0A5CB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAC71E94FBE200B0A5CB /* AppDelegate.swift */; }; 14 | 5DB2FACD1E94FBE200B0A5CB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5DB2FACB1E94FBE200B0A5CB /* Main.storyboard */; }; 15 | 5DB2FACF1E94FBE200B0A5CB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5DB2FACE1E94FBE200B0A5CB /* Assets.xcassets */; }; 16 | 5DB2FADA1E94FC3C00B0A5CB /* Cartfile in Resources */ = {isa = PBXBuildFile; fileRef = 5DB2FAD91E94FC3C00B0A5CB /* Cartfile */; }; 17 | 5DB2FAE61E95015100B0A5CB /* UserListConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAE01E95015100B0A5CB /* UserListConfigurator.swift */; }; 18 | 5DB2FAE71E95015100B0A5CB /* UserListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAE11E95015100B0A5CB /* UserListInteractor.swift */; }; 19 | 5DB2FAE81E95015100B0A5CB /* UserListModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAE21E95015100B0A5CB /* UserListModels.swift */; }; 20 | 5DB2FAE91E95015100B0A5CB /* UserListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAE31E95015100B0A5CB /* UserListPresenter.swift */; }; 21 | 5DB2FAEA1E95015100B0A5CB /* UserListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAE41E95015100B0A5CB /* UserListRouter.swift */; }; 22 | 5DB2FAEB1E95015100B0A5CB /* UserListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAE51E95015100B0A5CB /* UserListViewController.swift */; }; 23 | 5DB2FAED1E95030F00B0A5CB /* UserListViewController+TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAEC1E95030F00B0A5CB /* UserListViewController+TableView.swift */; }; 24 | 5DB2FAF51E9506EC00B0A5CB /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DB2FAF21E9506EC00B0A5CB /* Alamofire.framework */; }; 25 | 5DB2FAF61E9506EC00B0A5CB /* Kingfisher.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DB2FAF31E9506EC00B0A5CB /* Kingfisher.framework */; }; 26 | 5DB2FAF71E9506EC00B0A5CB /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DB2FAF41E9506EC00B0A5CB /* SwiftyJSON.framework */; }; 27 | 5DB2FAFA1E950A5000B0A5CB /* UserListWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAF91E950A5000B0A5CB /* UserListWorker.swift */; }; 28 | 5DB2FB011E950BA900B0A5CB /* UserDetailConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAFB1E950BA900B0A5CB /* UserDetailConfigurator.swift */; }; 29 | 5DB2FB021E950BA900B0A5CB /* UserDetailInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAFC1E950BA900B0A5CB /* UserDetailInteractor.swift */; }; 30 | 5DB2FB031E950BA900B0A5CB /* UserDetailModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAFD1E950BA900B0A5CB /* UserDetailModels.swift */; }; 31 | 5DB2FB041E950BA900B0A5CB /* UserDetailPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAFE1E950BA900B0A5CB /* UserDetailPresenter.swift */; }; 32 | 5DB2FB051E950BA900B0A5CB /* UserDetailRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FAFF1E950BA900B0A5CB /* UserDetailRouter.swift */; }; 33 | 5DB2FB061E950BA900B0A5CB /* UserDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FB001E950BA900B0A5CB /* UserDetailViewController.swift */; }; 34 | 5DB2FB0D1E950C4900B0A5CB /* UserStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FB0C1E950C4900B0A5CB /* UserStore.swift */; }; 35 | 5DB2FB101E950CD600B0A5CB /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FB0F1E950CD600B0A5CB /* User.swift */; }; 36 | 5DB2FB121E950CEE00B0A5CB /* Name.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FB111E950CEE00B0A5CB /* Name.swift */; }; 37 | 5DB2FB151E950D4200B0A5CB /* User+Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FB141E950D4200B0A5CB /* User+Network.swift */; }; 38 | 5DB2FB171E950D6F00B0A5CB /* Name+Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FB161E950D6F00B0A5CB /* Name+Network.swift */; }; 39 | 5DB2FB191E950DCF00B0A5CB /* UserNetworkStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FB181E950DCF00B0A5CB /* UserNetworkStore.swift */; }; 40 | 5DB2FB1B1E950DEA00B0A5CB /* UserNetworkRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FB1A1E950DEA00B0A5CB /* UserNetworkRouter.swift */; }; 41 | 5DB2FB1E1E950E5900B0A5CB /* SerializableUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2FB1D1E950E5900B0A5CB /* SerializableUtils.swift */; }; 42 | /* End PBXBuildFile section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 5D3865A31E962BCF00CFEDD1 /* UserDetailViewController+TableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserDetailViewController+TableView.swift"; sourceTree = ""; }; 46 | 5D3865A51E962DA400CFEDD1 /* UserTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserTableViewCell.swift; sourceTree = ""; }; 47 | 5D3865A61E962DA400CFEDD1 /* UserTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = UserTableViewCell.xib; sourceTree = ""; }; 48 | 5DB2FAC41E94FBE200B0A5CB /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 5DB2FAC71E94FBE200B0A5CB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 50 | 5DB2FACC1E94FBE200B0A5CB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 51 | 5DB2FACE1E94FBE200B0A5CB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 52 | 5DB2FAD31E94FBE200B0A5CB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | 5DB2FAD91E94FC3C00B0A5CB /* Cartfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Cartfile; sourceTree = ""; }; 54 | 5DB2FAE01E95015100B0A5CB /* UserListConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserListConfigurator.swift; sourceTree = ""; }; 55 | 5DB2FAE11E95015100B0A5CB /* UserListInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserListInteractor.swift; sourceTree = ""; }; 56 | 5DB2FAE21E95015100B0A5CB /* UserListModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserListModels.swift; sourceTree = ""; }; 57 | 5DB2FAE31E95015100B0A5CB /* UserListPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserListPresenter.swift; sourceTree = ""; }; 58 | 5DB2FAE41E95015100B0A5CB /* UserListRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserListRouter.swift; sourceTree = ""; }; 59 | 5DB2FAE51E95015100B0A5CB /* UserListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserListViewController.swift; sourceTree = ""; }; 60 | 5DB2FAEC1E95030F00B0A5CB /* UserListViewController+TableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserListViewController+TableView.swift"; sourceTree = ""; }; 61 | 5DB2FAF21E9506EC00B0A5CB /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/iOS/Alamofire.framework; sourceTree = ""; }; 62 | 5DB2FAF31E9506EC00B0A5CB /* Kingfisher.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kingfisher.framework; path = Carthage/Build/iOS/Kingfisher.framework; sourceTree = ""; }; 63 | 5DB2FAF41E9506EC00B0A5CB /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/iOS/SwiftyJSON.framework; sourceTree = ""; }; 64 | 5DB2FAF91E950A5000B0A5CB /* UserListWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserListWorker.swift; sourceTree = ""; }; 65 | 5DB2FAFB1E950BA900B0A5CB /* UserDetailConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDetailConfigurator.swift; sourceTree = ""; }; 66 | 5DB2FAFC1E950BA900B0A5CB /* UserDetailInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDetailInteractor.swift; sourceTree = ""; }; 67 | 5DB2FAFD1E950BA900B0A5CB /* UserDetailModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDetailModels.swift; sourceTree = ""; }; 68 | 5DB2FAFE1E950BA900B0A5CB /* UserDetailPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDetailPresenter.swift; sourceTree = ""; }; 69 | 5DB2FAFF1E950BA900B0A5CB /* UserDetailRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDetailRouter.swift; sourceTree = ""; }; 70 | 5DB2FB001E950BA900B0A5CB /* UserDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDetailViewController.swift; sourceTree = ""; }; 71 | 5DB2FB0C1E950C4900B0A5CB /* UserStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserStore.swift; sourceTree = ""; }; 72 | 5DB2FB0F1E950CD600B0A5CB /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; 73 | 5DB2FB111E950CEE00B0A5CB /* Name.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Name.swift; sourceTree = ""; }; 74 | 5DB2FB141E950D4200B0A5CB /* User+Network.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "User+Network.swift"; sourceTree = ""; }; 75 | 5DB2FB161E950D6F00B0A5CB /* Name+Network.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Name+Network.swift"; sourceTree = ""; }; 76 | 5DB2FB181E950DCF00B0A5CB /* UserNetworkStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserNetworkStore.swift; sourceTree = ""; }; 77 | 5DB2FB1A1E950DEA00B0A5CB /* UserNetworkRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserNetworkRouter.swift; sourceTree = ""; }; 78 | 5DB2FB1D1E950E5900B0A5CB /* SerializableUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SerializableUtils.swift; sourceTree = ""; }; 79 | /* End PBXFileReference section */ 80 | 81 | /* Begin PBXFrameworksBuildPhase section */ 82 | 5DB2FAC11E94FBE200B0A5CB /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | 5DB2FAF51E9506EC00B0A5CB /* Alamofire.framework in Frameworks */, 87 | 5DB2FAF61E9506EC00B0A5CB /* Kingfisher.framework in Frameworks */, 88 | 5DB2FAF71E9506EC00B0A5CB /* SwiftyJSON.framework in Frameworks */, 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | /* End PBXFrameworksBuildPhase section */ 93 | 94 | /* Begin PBXGroup section */ 95 | 5DB2FABB1E94FBE200B0A5CB = { 96 | isa = PBXGroup; 97 | children = ( 98 | 5DB2FAD91E94FC3C00B0A5CB /* Cartfile */, 99 | 5DB2FAC61E94FBE200B0A5CB /* Example */, 100 | 5DB2FAC51E94FBE200B0A5CB /* Products */, 101 | 5DB2FAF11E9506EC00B0A5CB /* Frameworks */, 102 | ); 103 | sourceTree = ""; 104 | }; 105 | 5DB2FAC51E94FBE200B0A5CB /* Products */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 5DB2FAC41E94FBE200B0A5CB /* Example.app */, 109 | ); 110 | name = Products; 111 | sourceTree = ""; 112 | }; 113 | 5DB2FAC61E94FBE200B0A5CB /* Example */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 5DB2FB1C1E950E4D00B0A5CB /* Common */, 117 | 5DB2FB071E950C1700B0A5CB /* Services */, 118 | 5DB2FB0E1E950CC200B0A5CB /* Models */, 119 | 5DB2FADD1E95010300B0A5CB /* Scenes */, 120 | 5DB2FAC71E94FBE200B0A5CB /* AppDelegate.swift */, 121 | 5DB2FACB1E94FBE200B0A5CB /* Main.storyboard */, 122 | 5DB2FACE1E94FBE200B0A5CB /* Assets.xcassets */, 123 | 5DB2FAD31E94FBE200B0A5CB /* Info.plist */, 124 | ); 125 | path = Example; 126 | sourceTree = ""; 127 | }; 128 | 5DB2FADD1E95010300B0A5CB /* Scenes */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 5DB2FADE1E95010300B0A5CB /* UserDetail */, 132 | 5DB2FADF1E95010300B0A5CB /* UserList */, 133 | ); 134 | path = Scenes; 135 | sourceTree = ""; 136 | }; 137 | 5DB2FADE1E95010300B0A5CB /* UserDetail */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 5DB2FAFB1E950BA900B0A5CB /* UserDetailConfigurator.swift */, 141 | 5DB2FAFC1E950BA900B0A5CB /* UserDetailInteractor.swift */, 142 | 5DB2FAFD1E950BA900B0A5CB /* UserDetailModels.swift */, 143 | 5DB2FAFE1E950BA900B0A5CB /* UserDetailPresenter.swift */, 144 | 5DB2FAFF1E950BA900B0A5CB /* UserDetailRouter.swift */, 145 | 5DB2FB001E950BA900B0A5CB /* UserDetailViewController.swift */, 146 | 5D3865A31E962BCF00CFEDD1 /* UserDetailViewController+TableView.swift */, 147 | ); 148 | path = UserDetail; 149 | sourceTree = ""; 150 | }; 151 | 5DB2FADF1E95010300B0A5CB /* UserList */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | 5DB2FAEE1E9505C400B0A5CB /* UI */, 155 | 5DB2FAE01E95015100B0A5CB /* UserListConfigurator.swift */, 156 | 5DB2FAE11E95015100B0A5CB /* UserListInteractor.swift */, 157 | 5DB2FAE21E95015100B0A5CB /* UserListModels.swift */, 158 | 5DB2FAE31E95015100B0A5CB /* UserListPresenter.swift */, 159 | 5DB2FAE41E95015100B0A5CB /* UserListRouter.swift */, 160 | 5DB2FAE51E95015100B0A5CB /* UserListViewController.swift */, 161 | 5DB2FAEC1E95030F00B0A5CB /* UserListViewController+TableView.swift */, 162 | 5DB2FAF91E950A5000B0A5CB /* UserListWorker.swift */, 163 | ); 164 | path = UserList; 165 | sourceTree = ""; 166 | }; 167 | 5DB2FAEE1E9505C400B0A5CB /* UI */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | 5D3865A51E962DA400CFEDD1 /* UserTableViewCell.swift */, 171 | 5D3865A61E962DA400CFEDD1 /* UserTableViewCell.xib */, 172 | ); 173 | path = UI; 174 | sourceTree = ""; 175 | }; 176 | 5DB2FAF11E9506EC00B0A5CB /* Frameworks */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 5DB2FAF21E9506EC00B0A5CB /* Alamofire.framework */, 180 | 5DB2FAF31E9506EC00B0A5CB /* Kingfisher.framework */, 181 | 5DB2FAF41E9506EC00B0A5CB /* SwiftyJSON.framework */, 182 | ); 183 | name = Frameworks; 184 | sourceTree = ""; 185 | }; 186 | 5DB2FB071E950C1700B0A5CB /* Services */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | 5DB2FB081E950C1700B0A5CB /* Stores */, 190 | 5DB2FB131E950D2200B0A5CB /* Mappers */, 191 | ); 192 | path = Services; 193 | sourceTree = ""; 194 | }; 195 | 5DB2FB081E950C1700B0A5CB /* Stores */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 5DB2FB091E950C1700B0A5CB /* Definitions */, 199 | 5DB2FB0A1E950C1700B0A5CB /* Network */, 200 | ); 201 | path = Stores; 202 | sourceTree = ""; 203 | }; 204 | 5DB2FB091E950C1700B0A5CB /* Definitions */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | 5DB2FB0C1E950C4900B0A5CB /* UserStore.swift */, 208 | ); 209 | path = Definitions; 210 | sourceTree = ""; 211 | }; 212 | 5DB2FB0A1E950C1700B0A5CB /* Network */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | 5DB2FB0B1E950C1700B0A5CB /* Router */, 216 | 5DB2FB181E950DCF00B0A5CB /* UserNetworkStore.swift */, 217 | ); 218 | path = Network; 219 | sourceTree = ""; 220 | }; 221 | 5DB2FB0B1E950C1700B0A5CB /* Router */ = { 222 | isa = PBXGroup; 223 | children = ( 224 | 5DB2FB1A1E950DEA00B0A5CB /* UserNetworkRouter.swift */, 225 | ); 226 | path = Router; 227 | sourceTree = ""; 228 | }; 229 | 5DB2FB0E1E950CC200B0A5CB /* Models */ = { 230 | isa = PBXGroup; 231 | children = ( 232 | 5DB2FB0F1E950CD600B0A5CB /* User.swift */, 233 | 5DB2FB111E950CEE00B0A5CB /* Name.swift */, 234 | ); 235 | path = Models; 236 | sourceTree = ""; 237 | }; 238 | 5DB2FB131E950D2200B0A5CB /* Mappers */ = { 239 | isa = PBXGroup; 240 | children = ( 241 | 5DB2FB141E950D4200B0A5CB /* User+Network.swift */, 242 | 5DB2FB161E950D6F00B0A5CB /* Name+Network.swift */, 243 | ); 244 | path = Mappers; 245 | sourceTree = ""; 246 | }; 247 | 5DB2FB1C1E950E4D00B0A5CB /* Common */ = { 248 | isa = PBXGroup; 249 | children = ( 250 | 5DB2FB1D1E950E5900B0A5CB /* SerializableUtils.swift */, 251 | ); 252 | path = Common; 253 | sourceTree = ""; 254 | }; 255 | /* End PBXGroup section */ 256 | 257 | /* Begin PBXNativeTarget section */ 258 | 5DB2FAC31E94FBE200B0A5CB /* Example */ = { 259 | isa = PBXNativeTarget; 260 | buildConfigurationList = 5DB2FAD61E94FBE200B0A5CB /* Build configuration list for PBXNativeTarget "Example" */; 261 | buildPhases = ( 262 | 5DB2FAC01E94FBE200B0A5CB /* Sources */, 263 | 5DB2FAC11E94FBE200B0A5CB /* Frameworks */, 264 | 5DB2FAC21E94FBE200B0A5CB /* Resources */, 265 | 5DB2FAF81E9506FB00B0A5CB /* Carthage dSYMs work around */, 266 | ); 267 | buildRules = ( 268 | ); 269 | dependencies = ( 270 | ); 271 | name = Example; 272 | productName = Example; 273 | productReference = 5DB2FAC41E94FBE200B0A5CB /* Example.app */; 274 | productType = "com.apple.product-type.application"; 275 | }; 276 | /* End PBXNativeTarget section */ 277 | 278 | /* Begin PBXProject section */ 279 | 5DB2FABC1E94FBE200B0A5CB /* Project object */ = { 280 | isa = PBXProject; 281 | attributes = { 282 | LastSwiftUpdateCheck = 0830; 283 | LastUpgradeCheck = 0830; 284 | ORGANIZATIONNAME = "HELM S.C.P."; 285 | TargetAttributes = { 286 | 5DB2FAC31E94FBE200B0A5CB = { 287 | CreatedOnToolsVersion = 8.3; 288 | ProvisioningStyle = Automatic; 289 | }; 290 | }; 291 | }; 292 | buildConfigurationList = 5DB2FABF1E94FBE200B0A5CB /* Build configuration list for PBXProject "Example" */; 293 | compatibilityVersion = "Xcode 3.2"; 294 | developmentRegion = English; 295 | hasScannedForEncodings = 0; 296 | knownRegions = ( 297 | en, 298 | Base, 299 | ); 300 | mainGroup = 5DB2FABB1E94FBE200B0A5CB; 301 | productRefGroup = 5DB2FAC51E94FBE200B0A5CB /* Products */; 302 | projectDirPath = ""; 303 | projectRoot = ""; 304 | targets = ( 305 | 5DB2FAC31E94FBE200B0A5CB /* Example */, 306 | ); 307 | }; 308 | /* End PBXProject section */ 309 | 310 | /* Begin PBXResourcesBuildPhase section */ 311 | 5DB2FAC21E94FBE200B0A5CB /* Resources */ = { 312 | isa = PBXResourcesBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | 5D3865A81E962DA400CFEDD1 /* UserTableViewCell.xib in Resources */, 316 | 5DB2FACF1E94FBE200B0A5CB /* Assets.xcassets in Resources */, 317 | 5DB2FADA1E94FC3C00B0A5CB /* Cartfile in Resources */, 318 | 5DB2FACD1E94FBE200B0A5CB /* Main.storyboard in Resources */, 319 | ); 320 | runOnlyForDeploymentPostprocessing = 0; 321 | }; 322 | /* End PBXResourcesBuildPhase section */ 323 | 324 | /* Begin PBXShellScriptBuildPhase section */ 325 | 5DB2FAF81E9506FB00B0A5CB /* Carthage dSYMs work around */ = { 326 | isa = PBXShellScriptBuildPhase; 327 | buildActionMask = 2147483647; 328 | files = ( 329 | ); 330 | inputPaths = ( 331 | "$(SRCROOT)/Carthage/Build/iOS/Kingfisher.framework", 332 | "$(SRCROOT)/Carthage/Build/iOS/Alamofire.framework", 333 | "$(SRCROOT)/Carthage/Build/iOS/SwiftyJSON.framework", 334 | ); 335 | name = "Carthage dSYMs work around"; 336 | outputPaths = ( 337 | ); 338 | runOnlyForDeploymentPostprocessing = 0; 339 | shellPath = /bin/sh; 340 | shellScript = "/usr/local/bin/carthage copy-frameworks\n"; 341 | }; 342 | /* End PBXShellScriptBuildPhase section */ 343 | 344 | /* Begin PBXSourcesBuildPhase section */ 345 | 5DB2FAC01E94FBE200B0A5CB /* Sources */ = { 346 | isa = PBXSourcesBuildPhase; 347 | buildActionMask = 2147483647; 348 | files = ( 349 | 5D3865A41E962BCF00CFEDD1 /* UserDetailViewController+TableView.swift in Sources */, 350 | 5D3865A71E962DA400CFEDD1 /* UserTableViewCell.swift in Sources */, 351 | 5DB2FB061E950BA900B0A5CB /* UserDetailViewController.swift in Sources */, 352 | 5DB2FB041E950BA900B0A5CB /* UserDetailPresenter.swift in Sources */, 353 | 5DB2FB011E950BA900B0A5CB /* UserDetailConfigurator.swift in Sources */, 354 | 5DB2FB031E950BA900B0A5CB /* UserDetailModels.swift in Sources */, 355 | 5DB2FB1B1E950DEA00B0A5CB /* UserNetworkRouter.swift in Sources */, 356 | 5DB2FB051E950BA900B0A5CB /* UserDetailRouter.swift in Sources */, 357 | 5DB2FB0D1E950C4900B0A5CB /* UserStore.swift in Sources */, 358 | 5DB2FAE61E95015100B0A5CB /* UserListConfigurator.swift in Sources */, 359 | 5DB2FAEB1E95015100B0A5CB /* UserListViewController.swift in Sources */, 360 | 5DB2FAED1E95030F00B0A5CB /* UserListViewController+TableView.swift in Sources */, 361 | 5DB2FAE91E95015100B0A5CB /* UserListPresenter.swift in Sources */, 362 | 5DB2FB171E950D6F00B0A5CB /* Name+Network.swift in Sources */, 363 | 5DB2FB1E1E950E5900B0A5CB /* SerializableUtils.swift in Sources */, 364 | 5DB2FAE71E95015100B0A5CB /* UserListInteractor.swift in Sources */, 365 | 5DB2FAEA1E95015100B0A5CB /* UserListRouter.swift in Sources */, 366 | 5DB2FAFA1E950A5000B0A5CB /* UserListWorker.swift in Sources */, 367 | 5DB2FB121E950CEE00B0A5CB /* Name.swift in Sources */, 368 | 5DB2FAE81E95015100B0A5CB /* UserListModels.swift in Sources */, 369 | 5DB2FB191E950DCF00B0A5CB /* UserNetworkStore.swift in Sources */, 370 | 5DB2FAC81E94FBE200B0A5CB /* AppDelegate.swift in Sources */, 371 | 5DB2FB021E950BA900B0A5CB /* UserDetailInteractor.swift in Sources */, 372 | 5DB2FB101E950CD600B0A5CB /* User.swift in Sources */, 373 | 5DB2FB151E950D4200B0A5CB /* User+Network.swift in Sources */, 374 | ); 375 | runOnlyForDeploymentPostprocessing = 0; 376 | }; 377 | /* End PBXSourcesBuildPhase section */ 378 | 379 | /* Begin PBXVariantGroup section */ 380 | 5DB2FACB1E94FBE200B0A5CB /* Main.storyboard */ = { 381 | isa = PBXVariantGroup; 382 | children = ( 383 | 5DB2FACC1E94FBE200B0A5CB /* Base */, 384 | ); 385 | name = Main.storyboard; 386 | sourceTree = ""; 387 | }; 388 | /* End PBXVariantGroup section */ 389 | 390 | /* Begin XCBuildConfiguration section */ 391 | 5DB2FAD41E94FBE200B0A5CB /* Debug */ = { 392 | isa = XCBuildConfiguration; 393 | buildSettings = { 394 | ALWAYS_SEARCH_USER_PATHS = NO; 395 | CLANG_ANALYZER_NONNULL = YES; 396 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 397 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 398 | CLANG_CXX_LIBRARY = "libc++"; 399 | CLANG_ENABLE_MODULES = YES; 400 | CLANG_ENABLE_OBJC_ARC = YES; 401 | CLANG_WARN_BOOL_CONVERSION = YES; 402 | CLANG_WARN_CONSTANT_CONVERSION = YES; 403 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 404 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 405 | CLANG_WARN_EMPTY_BODY = YES; 406 | CLANG_WARN_ENUM_CONVERSION = YES; 407 | CLANG_WARN_INFINITE_RECURSION = YES; 408 | CLANG_WARN_INT_CONVERSION = YES; 409 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 410 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 411 | CLANG_WARN_UNREACHABLE_CODE = YES; 412 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 413 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 414 | COPY_PHASE_STRIP = NO; 415 | DEBUG_INFORMATION_FORMAT = dwarf; 416 | ENABLE_STRICT_OBJC_MSGSEND = YES; 417 | ENABLE_TESTABILITY = YES; 418 | GCC_C_LANGUAGE_STANDARD = gnu99; 419 | GCC_DYNAMIC_NO_PIC = NO; 420 | GCC_NO_COMMON_BLOCKS = YES; 421 | GCC_OPTIMIZATION_LEVEL = 0; 422 | GCC_PREPROCESSOR_DEFINITIONS = ( 423 | "DEBUG=1", 424 | "$(inherited)", 425 | ); 426 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 427 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 428 | GCC_WARN_UNDECLARED_SELECTOR = YES; 429 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 430 | GCC_WARN_UNUSED_FUNCTION = YES; 431 | GCC_WARN_UNUSED_VARIABLE = YES; 432 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 433 | MTL_ENABLE_DEBUG_INFO = YES; 434 | ONLY_ACTIVE_ARCH = YES; 435 | SDKROOT = iphoneos; 436 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 437 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 438 | TARGETED_DEVICE_FAMILY = "1,2"; 439 | }; 440 | name = Debug; 441 | }; 442 | 5DB2FAD51E94FBE200B0A5CB /* Release */ = { 443 | isa = XCBuildConfiguration; 444 | buildSettings = { 445 | ALWAYS_SEARCH_USER_PATHS = NO; 446 | CLANG_ANALYZER_NONNULL = YES; 447 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 448 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 449 | CLANG_CXX_LIBRARY = "libc++"; 450 | CLANG_ENABLE_MODULES = YES; 451 | CLANG_ENABLE_OBJC_ARC = YES; 452 | CLANG_WARN_BOOL_CONVERSION = YES; 453 | CLANG_WARN_CONSTANT_CONVERSION = YES; 454 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 455 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 456 | CLANG_WARN_EMPTY_BODY = YES; 457 | CLANG_WARN_ENUM_CONVERSION = YES; 458 | CLANG_WARN_INFINITE_RECURSION = YES; 459 | CLANG_WARN_INT_CONVERSION = YES; 460 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 461 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 462 | CLANG_WARN_UNREACHABLE_CODE = YES; 463 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 464 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 465 | COPY_PHASE_STRIP = NO; 466 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 467 | ENABLE_NS_ASSERTIONS = NO; 468 | ENABLE_STRICT_OBJC_MSGSEND = YES; 469 | GCC_C_LANGUAGE_STANDARD = gnu99; 470 | GCC_NO_COMMON_BLOCKS = YES; 471 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 472 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 473 | GCC_WARN_UNDECLARED_SELECTOR = YES; 474 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 475 | GCC_WARN_UNUSED_FUNCTION = YES; 476 | GCC_WARN_UNUSED_VARIABLE = YES; 477 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 478 | MTL_ENABLE_DEBUG_INFO = NO; 479 | SDKROOT = iphoneos; 480 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 481 | TARGETED_DEVICE_FAMILY = "1,2"; 482 | VALIDATE_PRODUCT = YES; 483 | }; 484 | name = Release; 485 | }; 486 | 5DB2FAD71E94FBE200B0A5CB /* Debug */ = { 487 | isa = XCBuildConfiguration; 488 | buildSettings = { 489 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 490 | FRAMEWORK_SEARCH_PATHS = ( 491 | "$(inherited)", 492 | "$(PROJECT_DIR)/Carthage/Build/iOS", 493 | ); 494 | INFOPLIST_FILE = Example/Info.plist; 495 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 496 | PRODUCT_BUNDLE_IDENTIFIER = cat.helm.Example; 497 | PRODUCT_NAME = "$(TARGET_NAME)"; 498 | SWIFT_VERSION = 3.0; 499 | }; 500 | name = Debug; 501 | }; 502 | 5DB2FAD81E94FBE200B0A5CB /* Release */ = { 503 | isa = XCBuildConfiguration; 504 | buildSettings = { 505 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 506 | FRAMEWORK_SEARCH_PATHS = ( 507 | "$(inherited)", 508 | "$(PROJECT_DIR)/Carthage/Build/iOS", 509 | ); 510 | INFOPLIST_FILE = Example/Info.plist; 511 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 512 | PRODUCT_BUNDLE_IDENTIFIER = cat.helm.Example; 513 | PRODUCT_NAME = "$(TARGET_NAME)"; 514 | SWIFT_VERSION = 3.0; 515 | }; 516 | name = Release; 517 | }; 518 | /* End XCBuildConfiguration section */ 519 | 520 | /* Begin XCConfigurationList section */ 521 | 5DB2FABF1E94FBE200B0A5CB /* Build configuration list for PBXProject "Example" */ = { 522 | isa = XCConfigurationList; 523 | buildConfigurations = ( 524 | 5DB2FAD41E94FBE200B0A5CB /* Debug */, 525 | 5DB2FAD51E94FBE200B0A5CB /* Release */, 526 | ); 527 | defaultConfigurationIsVisible = 0; 528 | defaultConfigurationName = Release; 529 | }; 530 | 5DB2FAD61E94FBE200B0A5CB /* Build configuration list for PBXNativeTarget "Example" */ = { 531 | isa = XCConfigurationList; 532 | buildConfigurations = ( 533 | 5DB2FAD71E94FBE200B0A5CB /* Debug */, 534 | 5DB2FAD81E94FBE200B0A5CB /* Release */, 535 | ); 536 | defaultConfigurationIsVisible = 0; 537 | defaultConfigurationName = Release; 538 | }; 539 | /* End XCConfigurationList section */ 540 | }; 541 | rootObject = 5DB2FABC1E94FBE200B0A5CB /* Project object */; 542 | } 543 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright © 2017 HELM S.C.P. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /Example/Example/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 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 93 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /Example/Example/Common/SerializableUtils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SerializableUtils.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright © 2017 HELM S.C.P. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | import SwiftyJSON 12 | 13 | protocol ResponseObjectSerializable { 14 | init?(fromJSON json:JSON) 15 | } 16 | 17 | protocol ResponseCollectionSerializable { 18 | static func collection(fromJSON json:JSON) -> [Self]? 19 | } 20 | 21 | extension ResponseCollectionSerializable where Self:ResponseObjectSerializable { 22 | 23 | static func collection(fromJSON json:JSON) -> [Self]? { 24 | var items:[Self] = [] 25 | guard let itemsJSON = json.array else { 26 | print(json) 27 | return nil 28 | } 29 | for itemJSON in itemsJSON { 30 | if let item = Self(fromJSON: itemJSON) { 31 | items.append(item) 32 | } 33 | } 34 | return items 35 | } 36 | } 37 | 38 | extension DataRequest { 39 | 40 | func responseObject( 41 | queue: DispatchQueue? = nil, 42 | completionHandler: @escaping (DataResponse) -> Void) -> Self 43 | { 44 | let responseSerializer = DataResponseSerializer { request, response, data, error in 45 | guard error == nil else { return .failure(BackendError.network(error: error!)) } 46 | 47 | let jsonResponseSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments) 48 | let result = jsonResponseSerializer.serializeResponse(request, response, data, nil) 49 | 50 | guard case let .success(jsonObject) = result else { 51 | return .failure(BackendError.jsonSerialization(error: result.error!)) 52 | } 53 | 54 | let json = JSON(jsonObject) 55 | 56 | guard let responseObject = T(fromJSON: json) else { 57 | return .failure(BackendError.objectSerialization(reason: "JSON could not be serialized: \(json)")) 58 | } 59 | 60 | return .success(responseObject) 61 | } 62 | 63 | return response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler) 64 | } 65 | 66 | @discardableResult 67 | func responseCollection( 68 | queue: DispatchQueue? = nil, 69 | completionHandler: @escaping (DataResponse<[T]>) -> Void) -> Self 70 | { 71 | let responseSerializer = DataResponseSerializer<[T]> { request, response, data, error in 72 | guard error == nil else { return .failure(BackendError.network(error: error!)) } 73 | 74 | let jsonSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments) 75 | let result = jsonSerializer.serializeResponse(request, response, data, nil) 76 | 77 | guard case let .success(jsonObject) = result else { 78 | return .failure(BackendError.jsonSerialization(error: result.error!)) 79 | } 80 | 81 | let json = JSON(jsonObject) 82 | 83 | guard response != nil else { 84 | let reason = "Response collection could not be serialized due to nil response." 85 | return .failure(BackendError.objectSerialization(reason: reason)) 86 | } 87 | 88 | guard let items = T.collection(fromJSON:json) else { 89 | let reason = "Response collection could not be serialized due to nil serialization." 90 | return .failure(BackendError.objectSerialization(reason: reason)) 91 | 92 | } 93 | 94 | return .success(items) 95 | } 96 | 97 | return response(responseSerializer: responseSerializer, completionHandler: completionHandler) 98 | } 99 | 100 | } 101 | 102 | enum BackendError: Error { 103 | case network(error: Error) // Capture any underlying Error from the URLSession API 104 | case dataSerialization(error: Error) 105 | case jsonSerialization(error: Error) 106 | case xmlSerialization(error: Error) 107 | case objectSerialization(reason: String) 108 | } 109 | -------------------------------------------------------------------------------- /Example/Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/Example/Models/Name.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Name.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright © 2017 HELM S.C.P. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Name { 12 | 13 | let firstName: String 14 | let lastName: String 15 | let title: String 16 | 17 | init(firstName: String, lastName: String, title: String) { 18 | self.firstName = firstName 19 | self.lastName = lastName 20 | self.title = title 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Example/Example/Models/User.swift: -------------------------------------------------------------------------------- 1 | // 2 | // User.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright © 2017 HELM S.C.P. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct User { 12 | 13 | let name: Name 14 | let gender: String 15 | let email: String 16 | let mobile: String 17 | let imagePath: String 18 | let thumbImagePath: String 19 | 20 | init(name: Name, gender: String, email: String, mobile: String, imagePath: String, thumbImagePath: String) { 21 | self.name = name 22 | self.gender = gender 23 | self.email = email 24 | self.mobile = mobile 25 | self.imagePath = imagePath 26 | self.thumbImagePath = thumbImagePath 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserDetail/UserDetailConfigurator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDetailConfigurator.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | import UIKit 12 | 13 | // MARK: Connect View, Interactor, and Presenter 14 | 15 | extension UserDetailInteractor: UserDetailViewControllerOutput, UserDetailRouterDataSource, UserDetailRouterDataDestination { 16 | } 17 | 18 | extension UserDetailPresenter: UserDetailInteractorOutput { 19 | } 20 | 21 | class UserDetailConfigurator { 22 | // MARK: Object lifecycle 23 | 24 | static let sharedInstance = UserDetailConfigurator() 25 | 26 | private init() {} 27 | 28 | // MARK: Configuration 29 | 30 | func configure(viewController: UserDetailViewController) { 31 | 32 | let presenter = UserDetailPresenter() 33 | presenter.output = viewController 34 | 35 | let interactor = UserDetailInteractor() 36 | interactor.output = presenter 37 | 38 | let router = UserDetailRouter(viewController: viewController, dataSource: interactor, dataDestination: interactor) 39 | 40 | viewController.output = interactor 41 | viewController.router = router 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserDetail/UserDetailInteractor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDetailInteractor.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | protocol UserDetailInteractorInput { 12 | func getUser(request: UserDetailScene.GetUser.Request) 13 | } 14 | 15 | protocol UserDetailInteractorOutput { 16 | func presentUser(response: UserDetailScene.GetUser.Response) 17 | } 18 | 19 | protocol UserDetailDataSource { 20 | 21 | } 22 | 23 | protocol UserDetailDataDestination { 24 | var user: User! { get set } 25 | } 26 | 27 | class UserDetailInteractor: UserDetailInteractorInput, UserDetailDataSource, UserDetailDataDestination { 28 | 29 | var output: UserDetailInteractorOutput? 30 | 31 | var user: User! 32 | 33 | // MARK: Business logic 34 | 35 | func getUser(request: UserDetailScene.GetUser.Request) { 36 | 37 | // NOTE: Pass the result to the Presenter 38 | 39 | let response = UserDetailScene.GetUser.Response(user: user) 40 | output?.presentUser(response: response) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserDetail/UserDetailModels.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDetailModels.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | // Type "usecase" for some magic! 11 | 12 | struct UserDetailScene { 13 | 14 | struct GetUser { 15 | 16 | struct Request { 17 | 18 | } 19 | 20 | struct Response { 21 | var user: User 22 | } 23 | 24 | struct ViewModel { 25 | let imagePath: String 26 | let atributes: [Atribute] 27 | 28 | struct Atribute { 29 | let title: String 30 | let value: String 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserDetail/UserDetailPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDetailPresenter.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | protocol UserDetailPresenterInput { 12 | func presentUser(response: UserDetailScene.GetUser.Response) 13 | } 14 | 15 | protocol UserDetailPresenterOutput: class { 16 | func displayUser(viewModel: UserDetailScene.GetUser.ViewModel) 17 | } 18 | 19 | class UserDetailPresenter: UserDetailPresenterInput { 20 | 21 | weak var output: UserDetailPresenterOutput? 22 | 23 | // MARK: Presentation logic 24 | 25 | func presentUser(response: UserDetailScene.GetUser.Response) { 26 | let user = response.user 27 | 28 | let viewModel = mapUserToViewModel(user: user) 29 | 30 | output?.displayUser(viewModel: viewModel) 31 | } 32 | 33 | func mapUserToViewModel(user: User) -> UserDetailScene.GetUser.ViewModel { 34 | 35 | let userNameData = user.name 36 | let userName = userNameData.title.capitalized + ". " + userNameData.firstName.capitalized + " " + userNameData.lastName.capitalized 37 | 38 | let nameAtribute = UserDetailScene.GetUser.ViewModel.Atribute(title: "Name: ", value: userName) 39 | let emailAtribute = UserDetailScene.GetUser.ViewModel.Atribute(title: "Email: ", value: user.email) 40 | let mobileAtribute = UserDetailScene.GetUser.ViewModel.Atribute(title: "Mobile: ", value: user.mobile) 41 | 42 | let atributes = [nameAtribute, emailAtribute, mobileAtribute] 43 | 44 | return UserDetailScene.GetUser.ViewModel(imagePath: user.imagePath, atributes: atributes) 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserDetail/UserDetailRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDetailRouter.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | import UIKit 12 | 13 | protocol UserDetailRouterInput { 14 | 15 | } 16 | 17 | protocol UserDetailRouterDataSource: class { 18 | 19 | } 20 | 21 | protocol UserDetailRouterDataDestination: class { 22 | var user: User! { get set } 23 | } 24 | 25 | class UserDetailRouter: UserDetailRouterInput { 26 | 27 | weak var viewController: UserDetailViewController! 28 | weak private var dataSource: UserDetailRouterDataSource! 29 | weak var dataDestination: UserDetailRouterDataDestination! 30 | 31 | init(viewController: UserDetailViewController, dataSource: UserDetailRouterDataSource, dataDestination: UserDetailRouterDataDestination) { 32 | self.viewController = viewController 33 | self.dataSource = dataSource 34 | self.dataDestination = dataDestination 35 | } 36 | 37 | // MARK: Navigation 38 | 39 | // MARK: Communication 40 | 41 | func passDataToNextScene(for segue: UIStoryboardSegue) { 42 | // NOTE: Teach the router which scenes it can communicate with 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserDetail/UserDetailViewController+TableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDetailViewController+TableView.swift 3 | // Example 4 | // 5 | // Created by Joel on 06/04/2017. 6 | // Copyright © 2017 HELM S.C.P. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Kingfisher 11 | 12 | extension UserDetailViewController: UITableViewDelegate, UITableViewDataSource { 13 | 14 | func numberOfSections(in tableView: UITableView) -> Int { 15 | return 1 16 | } 17 | 18 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 19 | return atributes.count 20 | } 21 | 22 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 23 | if let atributeCell = tableView.dequeueReusableCell(withIdentifier: "AtributeCell") { 24 | atributeCell.textLabel?.text = atributes[indexPath.row].title 25 | atributeCell.detailTextLabel?.text = atributes[indexPath.row].value 26 | 27 | return atributeCell 28 | } 29 | 30 | return UITableViewCell() 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserDetail/UserDetailViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDetailViewController.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | import UIKit 12 | 13 | protocol UserDetailViewControllerInput { 14 | func displayUser(viewModel: UserDetailScene.GetUser.ViewModel) 15 | } 16 | 17 | protocol UserDetailViewControllerOutput { 18 | func getUser(request: UserDetailScene.GetUser.Request) 19 | } 20 | 21 | class UserDetailViewController: UIViewController, UserDetailViewControllerInput { 22 | 23 | var output: UserDetailViewControllerOutput? 24 | var router: UserDetailRouter? 25 | 26 | @IBOutlet weak var userImage: UIImageView! 27 | @IBOutlet weak var userDataTableView: UITableView! 28 | 29 | var atributes: [UserDetailScene.GetUser.ViewModel.Atribute] = [] 30 | 31 | // MARK: Object lifecycle 32 | 33 | override func awakeFromNib() { 34 | super.awakeFromNib() 35 | UserDetailConfigurator.sharedInstance.configure(viewController: self) 36 | } 37 | 38 | // MARK: View lifecycle 39 | 40 | override func viewDidLoad() { 41 | super.viewDidLoad() 42 | getUser() 43 | } 44 | 45 | // MARK: Requests 46 | 47 | func getUser() { 48 | let request = UserDetailScene.GetUser.Request() 49 | output?.getUser(request: request) 50 | } 51 | 52 | // MARK: Display logic 53 | 54 | func displayUser(viewModel: UserDetailScene.GetUser.ViewModel) { 55 | 56 | if let url = URL(string: viewModel.imagePath) { 57 | self.userImage.kf.setImage(with: url) 58 | } 59 | 60 | atributes = viewModel.atributes 61 | userDataTableView.reloadData() 62 | } 63 | 64 | 65 | } 66 | 67 | //This should be on configurator but for some reason storyboard doesn't detect ViewController's name if placed there 68 | extension UserDetailViewController: UserDetailPresenterOutput { 69 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 70 | router?.passDataToNextScene(for: segue) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserList/UI/UserTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserTableViewCell.swift 3 | // Example 4 | // 5 | // Created by Joel on 06/04/2017. 6 | // Copyright © 2017 HELM S.C.P. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class UserTableViewCell: UITableViewCell { 12 | 13 | @IBOutlet weak var userImage: UIImageView! 14 | @IBOutlet weak var userName: UILabel! 15 | @IBOutlet weak var userEmail: UILabel! 16 | 17 | override func awakeFromNib() { 18 | super.awakeFromNib() 19 | } 20 | 21 | override func setSelected(_ selected: Bool, animated: Bool) { 22 | super.setSelected(selected, animated: animated) 23 | } 24 | 25 | func set(user: UserListScene.GetUser.ViewModel.User) { 26 | self.userName.text = user.name 27 | self.userEmail.text = user.email 28 | 29 | if let url = URL(string: user.imagePath) { 30 | self.userImage.kf.setImage(with: url) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserList/UI/UserTableViewCell.xib: -------------------------------------------------------------------------------- 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 | 42 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserList/UserListConfigurator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserListConfigurator.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | import UIKit 12 | 13 | // MARK: Connect View, Interactor, and Presenter 14 | 15 | extension UserListInteractor: UserListViewControllerOutput, UserListRouterDataSource, UserListRouterDataDestination { 16 | } 17 | 18 | extension UserListPresenter: UserListInteractorOutput { 19 | } 20 | 21 | class UserListConfigurator { 22 | // MARK: Object lifecycle 23 | 24 | static let sharedInstance = UserListConfigurator() 25 | 26 | private init() {} 27 | 28 | // MARK: Configuration 29 | 30 | func configure(viewController: UserListViewController) { 31 | 32 | let presenter = UserListPresenter() 33 | presenter.output = viewController 34 | 35 | let interactor = UserListInteractor() 36 | interactor.output = presenter 37 | 38 | let router = UserListRouter(viewController: viewController, dataSource: interactor, dataDestination: interactor) 39 | 40 | viewController.output = interactor 41 | viewController.router = router 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserList/UserListInteractor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserListInteractor.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | protocol UserListInteractorInput { 12 | func getUser(request: UserListScene.GetUser.Request) 13 | func selectUser(request: UserListScene.SelectUser.Request) 14 | } 15 | 16 | protocol UserListInteractorOutput { 17 | func presentUser(response: UserListScene.GetUser.Response) 18 | } 19 | 20 | protocol UserListDataSource { 21 | var selectedUser: User! { get } 22 | } 23 | 24 | protocol UserListDataDestination { 25 | 26 | } 27 | 28 | class UserListInteractor: UserListInteractorInput, UserListDataSource, UserListDataDestination { 29 | 30 | var output: UserListInteractorOutput? 31 | var worker: UserListWorker? 32 | 33 | var users: [User] = [] 34 | var selectedUser: User! 35 | 36 | // MARK: Business logic 37 | 38 | func getUser(request: UserListScene.GetUser.Request) 39 | { 40 | worker = UserListWorker(store: UserNetworkStore()) 41 | worker?.getUser {(result: UserStoreResult) -> Void in 42 | 43 | switch result { 44 | case .success(let user): 45 | self.users.insert(user, at: 0) 46 | let response = UserListScene.GetUser.Response(newUser: user) 47 | self.output?.presentUser(response: response) 48 | case .failure(let error): 49 | print(error) 50 | } 51 | } 52 | } 53 | 54 | func selectUser(request: UserListScene.SelectUser.Request) { 55 | selectedUser = users[request.index] 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserList/UserListModels.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserListModels.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | // Type "usecase" for some magic! 11 | 12 | struct UserListScene { 13 | 14 | struct GetUser { 15 | 16 | struct Request { 17 | 18 | } 19 | 20 | struct Response { 21 | var newUser: User 22 | } 23 | 24 | struct ViewModel { 25 | let user: User 26 | 27 | struct User { 28 | let name: String 29 | let email: String 30 | let imagePath: String 31 | } 32 | } 33 | } 34 | 35 | struct SelectUser { 36 | 37 | struct Request { 38 | let index:Int 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserList/UserListPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserListPresenter.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | protocol UserListPresenterInput { 12 | func presentUser(response: UserListScene.GetUser.Response) 13 | } 14 | 15 | protocol UserListPresenterOutput: class { 16 | func displayUser(viewModel: UserListScene.GetUser.ViewModel) 17 | } 18 | 19 | class UserListPresenter: UserListPresenterInput { 20 | 21 | weak var output: UserListPresenterOutput? 22 | 23 | // MARK: Presentation logic 24 | 25 | func presentUser(response: UserListScene.GetUser.Response) 26 | { 27 | // NOTE: Format the response from the Interactor and pass the result back to the View Controller 28 | 29 | let user = response.newUser 30 | 31 | let userNameData = user.name 32 | let userName = userNameData.title.capitalized + ". " + userNameData.firstName.capitalized + " " + userNameData.lastName.capitalized 33 | 34 | let userViewModel = UserListScene.GetUser.ViewModel.User(name: userName, email: user.email, imagePath: user.thumbImagePath) 35 | 36 | let viewModel = UserListScene.GetUser.ViewModel(user: userViewModel) 37 | 38 | output?.displayUser(viewModel: viewModel) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserList/UserListRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserListRouter.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | import UIKit 12 | 13 | protocol UserListRouterInput { 14 | func navigateToUserDetailScene() 15 | } 16 | 17 | protocol UserListRouterDataSource: class { 18 | var selectedUser: User! { get } 19 | } 20 | 21 | protocol UserListRouterDataDestination: class { 22 | 23 | } 24 | 25 | class UserListRouter: UserListRouterInput { 26 | 27 | weak var viewController: UserListViewController! 28 | weak private var dataSource: UserListRouterDataSource! 29 | weak var dataDestination: UserListRouterDataDestination! 30 | 31 | struct SegueIdentifiers { 32 | static let userDetail = "UserDetailScene" 33 | } 34 | 35 | init(viewController: UserListViewController, dataSource: UserListRouterDataSource, dataDestination: UserListRouterDataDestination) { 36 | self.viewController = viewController 37 | self.dataSource = dataSource 38 | self.dataDestination = dataDestination 39 | } 40 | 41 | // MARK: Navigation 42 | 43 | func navigateToUserDetailScene() 44 | { 45 | viewController.performSegue(withIdentifier: SegueIdentifiers.userDetail, sender: viewController) 46 | } 47 | 48 | // MARK: Communication 49 | 50 | func passDataToNextScene(for segue: UIStoryboardSegue) { 51 | // NOTE: Teach the router which scenes it can communicate with 52 | 53 | guard let segueIdentifier = segue.identifier else { 54 | return 55 | } 56 | 57 | switch segueIdentifier { 58 | case SegueIdentifiers.userDetail: 59 | passDataToUserDetailScene(for: segue) 60 | default: 61 | return 62 | } 63 | } 64 | 65 | func passDataToUserDetailScene(for segue: UIStoryboardSegue) 66 | { 67 | // NOTE: Teach the router how to pass data to the next scene 68 | 69 | if let userDetailViewController = segue.destination as? UserDetailViewController { 70 | userDetailViewController.router?.dataDestination.user = dataSource.selectedUser 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserList/UserListViewController+TableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserListViewController+TableView.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright © 2017 HELM S.C.P. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UserListViewController: UITableViewDelegate, UITableViewDataSource { 12 | 13 | func configureTableViewOnLoad() { 14 | userListTableView.register(UINib(nibName: "UserTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: cellIdentifiers.userCell) 15 | } 16 | 17 | func numberOfSections(in tableView: UITableView) -> Int { 18 | return 1 19 | } 20 | 21 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 22 | return users.count 23 | } 24 | 25 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 26 | let displayUser = users[indexPath.row] 27 | 28 | if let userCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifiers.userCell) as? UserTableViewCell { 29 | userCell.set(user: displayUser) 30 | 31 | return userCell 32 | } 33 | 34 | return UITableViewCell() 35 | } 36 | 37 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 38 | let request = UserListScene.SelectUser.Request(index: indexPath.row) 39 | output?.selectUser(request: request) 40 | router?.navigateToUserDetailScene() 41 | tableView.deselectRow(at: indexPath, animated: true) 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserList/UserListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserListViewController.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | import UIKit 12 | 13 | protocol UserListViewControllerInput { 14 | func displayUser(viewModel: UserListScene.GetUser.ViewModel) 15 | } 16 | 17 | protocol UserListViewControllerOutput { 18 | func getUser(request: UserListScene.GetUser.Request) 19 | func selectUser(request: UserListScene.SelectUser.Request) 20 | } 21 | 22 | class UserListViewController: UIViewController, UserListViewControllerInput { 23 | 24 | var output: UserListViewControllerOutput? 25 | var router: UserListRouter? 26 | var users: [UserListScene.GetUser.ViewModel.User] = [] 27 | 28 | @IBOutlet weak var userListTableView: UITableView! 29 | 30 | struct cellIdentifiers { 31 | static let userCell = "userCell" 32 | } 33 | 34 | // MARK: Object lifecycle 35 | 36 | override func awakeFromNib() { 37 | super.awakeFromNib() 38 | UserListConfigurator.sharedInstance.configure(viewController: self) 39 | } 40 | 41 | // MARK: View lifecycle 42 | 43 | override func viewDidLoad() { 44 | super.viewDidLoad() 45 | configureTableViewOnLoad() 46 | } 47 | 48 | // MARK: Requests 49 | 50 | func requestGetUser() { 51 | let request = UserListScene.GetUser.Request() 52 | output?.getUser(request: request) 53 | } 54 | 55 | // MARK: Display logic 56 | 57 | func displayUser(viewModel: UserListScene.GetUser.ViewModel) { 58 | let user = viewModel.user 59 | users.insert(user, at: 0) 60 | userListTableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .right) 61 | } 62 | 63 | // MARK: UI events 64 | 65 | @IBAction func addUserButtonClicked(_ sender: UIBarButtonItem) { 66 | requestGetUser() 67 | } 68 | 69 | 70 | } 71 | 72 | //This should be on configurator but for some reason storyboard doesn't detect ViewController's name if placed there 73 | extension UserListViewController: UserListPresenterOutput { 74 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 75 | router?.passDataToNextScene(for: segue) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Example/Example/Scenes/UserList/UserListWorker.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserListWorker.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | class UserListWorker { 12 | // MARK: Business Logic 13 | 14 | let store: UserStore 15 | 16 | init(store: UserStore) { 17 | self.store = store 18 | } 19 | 20 | func getUser(completionHandler: @escaping (UserStoreResult) -> Void){ 21 | store.getUser(completion: completionHandler) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Example/Example/Services/Mappers/Name+Network.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Name+API.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright © 2017 HELM S.C.P. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftyJSON 11 | 12 | extension Name: ResponseObjectSerializable { 13 | 14 | init?(fromJSON json: JSON) { 15 | 16 | guard let firstName = json["first"].string 17 | ,let lastName = json["last"].string 18 | ,let title = json["title"].string else { 19 | return nil 20 | } 21 | 22 | self.firstName = firstName 23 | self.lastName = lastName 24 | self.title = title 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Example/Example/Services/Mappers/User+Network.swift: -------------------------------------------------------------------------------- 1 | // 2 | // User+API.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright © 2017 HELM S.C.P. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftyJSON 11 | 12 | extension User: ResponseObjectSerializable { 13 | 14 | init?(fromJSON json: JSON) { 15 | 16 | let userData = json["results"][0] 17 | let nameData = userData["name"] 18 | 19 | guard let mobile = userData["cell"].string 20 | ,let email = userData["email"].string 21 | ,let gender = userData["gender"].string 22 | ,let imagePath = userData["picture"]["large"].string 23 | ,let thumbImagePath = userData["picture"]["thumbnail"].string 24 | ,let name = Name(fromJSON: nameData) else { 25 | 26 | return nil 27 | } 28 | 29 | self.mobile = mobile 30 | self.email = email 31 | self.gender = gender 32 | self.imagePath = imagePath 33 | self.thumbImagePath = thumbImagePath 34 | self.name = name 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Example/Example/Services/Stores/Definitions/UserStore.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserStore.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright (c) 2017 HELM S.C.P. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift HELM Xcode Templates 9 | // 10 | 11 | protocol UserStore { 12 | func getUser(completion: @escaping UserStoreGetUserCompletionHandler) 13 | } 14 | 15 | typealias UserStoreGetUserCompletionHandler = (UserStoreResult) -> Void 16 | 17 | enum UserStoreResult { 18 | case success(result: U) 19 | case failure(error: UserStoreError) 20 | } 21 | 22 | enum UserStoreEmptyResult { 23 | case success 24 | case failure(error: UserStoreError) 25 | } 26 | 27 | enum UserStoreError: Equatable, Error { 28 | case cannotGet(String) 29 | } 30 | 31 | func ==(lhs: UserStoreError, rhs: UserStoreError) -> Bool { 32 | switch (lhs, rhs) { 33 | case (.cannotGet(let a), .cannotGet(let b)) where a == b: return true 34 | default: 35 | return false 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Example/Example/Services/Stores/Network/Router/UserNetworkRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserNetworkRouter.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright © 2017 HELM S.C.P. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | 12 | enum UserNetworkRouter:URLRequestConvertible { 13 | 14 | static let baseURL = "https://randomuser.me/api/" 15 | 16 | case getUser() 17 | 18 | func asURLRequest() throws -> URLRequest { 19 | var request: URLRequest! 20 | 21 | switch self { 22 | case .getUser(): 23 | let url = URL(string: UserNetworkRouter.baseURL)! 24 | request = URLRequest(url: url) 25 | request.httpMethod = "GET" 26 | } 27 | 28 | return try Alamofire.URLEncoding().encode(request, with: nil) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Example/Example/Services/Stores/Network/UserNetworkStore.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserNetworkStore.swift 3 | // Example 4 | // 5 | // Created by Joel on 05/04/2017. 6 | // Copyright © 2017 HELM S.C.P. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | 12 | class UserNetworkStore: UserStore { 13 | 14 | func getUser(completion: @escaping UserStoreGetUserCompletionHandler) { 15 | _ = Alamofire.request(UserNetworkRouter.getUser()) 16 | .validate() 17 | .responseObject { (response: DataResponse) in 18 | switch response.result { 19 | case .success(let user): 20 | completion(.success(result: user)) 21 | case .failure(let error): 22 | completion(.failure(error: UserStoreError.cannotGet("Cannot get user \(error)"))) 23 | } 24 | } 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Example/cartupdate.sh: -------------------------------------------------------------------------------- 1 | carthage update --platform iOS --no-use-binaries -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Original work Copyright (c) 2015 Raymond Law (http://clean-swift.com) 4 | Modified work Copyright (c) 2016 Miguel Berrocal HELM S.C.P (www.helm.cat) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | XCODE_USER_TEMPLATES_DIR=~/Library/Developer/Xcode/Templates/File\ Templates 2 | XCODE_USER_SNIPPETS_DIR=~/Library/Developer/Xcode/UserData/CodeSnippets 3 | SNIPPETS_PREFIX=clean-swift 4 | 5 | TEMPLATES_DIR=Clean\ Swift\ HELM 6 | SNIPPETS_DIR=Snippets 7 | 8 | install:install_templates install_snippets 9 | @echo "Install Done" 10 | 11 | install_templates: 12 | @mkdir -p $(XCODE_USER_TEMPLATES_DIR) 13 | @rm -fR $(XCODE_USER_TEMPLATES_DIR)/$(TEMPLATES_DIR) 14 | @cp -R $(TEMPLATES_DIR) $(XCODE_USER_TEMPLATES_DIR) 15 | 16 | install_snippets: 17 | @mkdir -p $(XCODE_USER_SNIPPETS_DIR) 18 | @rm -fR $(XCODE_USER_SNIPPETS_DIR)/$(SNIPPETS_PREFIX)* 19 | @cp $(SNIPPETS_DIR)/* $(XCODE_USER_SNIPPETS_DIR) 20 | @echo "Restart Xcode to see changes!" 21 | 22 | uninstall_templates: 23 | @rm -fR $(XCODE_USER_TEMPLATES_DIR)/$(TEMPLATES_DIR) 24 | 25 | uninstall_snippets: 26 | @rm -fR $(XCODE_USER_SNIPPETS_DIR)/$(SNIPPETS_PREFIX)* 27 | 28 | uninstall: uninstall_templates uninstall_snippets 29 | @echo "Uninstall Done" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clean-swift templates 2 | 3 | This is a modification of Clean Swift Templates (http://clean-swift.com) made by HELM (www.helm.cat) 4 | 5 | To learn more about Clean Swift and the VIP cycle, read: 6 | 7 | http://clean-swift.com/clean-swift-ios-architecture 8 | 9 | # Changelog 10 | 11 | This modification aims to create work-ready templates and snippets to achieve the maximum efficiency for people who are already familiar with them. Furthermore we added some extra features in order to attempt to solve some issues. 12 | 13 | Here is a list of what is modified: 14 | * Indent is changed to a standarized 4-spaces indent 15 | * Braces follow the OTBS (https://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS) 16 | * Deleted all example functions (doSomething, presentSomething, etc.) aswell as example models 17 | * Deleted worker auto-creation from Scene template 18 | 19 | Added features: 20 | * Awesome snippet to create usecases 21 | * New data-passing method 22 | * Added Store Template 23 | 24 | ## Snippet 25 | ![alt text](http://helm.cat/assets/github-images/usecase-snippet.gif "Use Case Snippet") 26 | 27 | ## New data-passing method 28 | Previously to pass data we need to do something like this in the source Router: 29 | ```swift 30 | let user = sourceViewController.output.selectedUser 31 | destinationViewController.output.user = user 32 | ``` 33 | We think this is wrong because: 34 | 35 | 1. We are not trying to output anything from the ViewController. 36 | 2. We are assuming the output === Interactor and the architecture loses sense (no component should know about what kind of object its output/input is). 37 | 3. We dont want the ViewController to know anything about Business model. 38 | 4. We want the Interactor to handle this data but we don't want the ViewController to know anything about it. 39 | 40 | So we added 2 new protocols on the router 41 | 42 | ```swift 43 | protocol RouterDataSource: class { 44 | 45 | } 46 | protocol RouterDataDestination: class { 47 | 48 | } 49 | ``` 50 | - The RouterDataSource protocol is used to determine what business data has to be passed somewhere. 51 | - The RouterDataDestination protocol is used to determine what data has to be received and handled by this scene. 52 | 53 | So following the example before we would add this in the source Router: 54 | ```swift 55 | protocol UserListRouterDataSource: class { 56 | var selectedUser: User! { get } 57 | } 58 | 59 | protocol UserListRouterDataDestination: class { 60 | 61 | } 62 | ``` 63 | 64 | And this in the destination: 65 | ```swift 66 | protocol UserDetailRouterDataSource: class { 67 | 68 | } 69 | 70 | protocol UserDetailRouterDataDestination: class { 71 | var user: User! { get set } 72 | } 73 | ``` 74 | 75 | As we added a dataSource object and a dataDestination object in the Router, we can now do this: 76 | 77 | ``` 78 | let user = dataSource.selectedUser 79 | userDetailViewController.router.dataDestination.user = user 80 | ``` 81 | 82 | As previously mentioned we believe this handling should be done by the Interactor aswell but without the ViewController knowing it so we added the protocols there and changed the Configurator.swift in order to connect both protocols. 83 | 84 | So the source Interactor would look like this: 85 | ```swift 86 | protocol UserListDataSource { 87 | var selectedUser: User! { get } 88 | } 89 | 90 | protocol UserListDataDestination { 91 | 92 | } 93 | 94 | class UserListInteractor: UserListInteractorInput, UserListDataSource, UserListDataDestination { 95 | ``` 96 | 97 | And as you would assume, the destination Interactor looks like this: 98 | 99 | ```swift 100 | protocol UserDetailDataSource { 101 | 102 | } 103 | 104 | protocol UserDetailDataDestination { 105 | var user: User! { get set } 106 | } 107 | 108 | class UserDetailInteractor: UserDetailInteractorInput, UserDetailDataSource, UserDetailDataDestination { 109 | ``` 110 | 111 | You can see a working example in the Example folder. 112 | 113 | # Installation 114 | 115 | To install the Clean Swift Xcode HELM templates and snippets, run: 116 | ``` 117 | ./configure 118 | make install 119 | ``` 120 | To uninstall the Clean Swift Xcode templates and snippets, run: 121 | ``` 122 | make uninstall 123 | ``` 124 | 125 | To try the Example project you need carthage: 126 | ``` 127 | brew update 128 | brew install carthage 129 | ``` 130 | 131 | Then run 132 | ``` 133 | ./cartupdate.sh 134 | ``` 135 | 136 | In the project folder (/Example) 137 | -------------------------------------------------------------------------------- /Snippets/clean-swift-use-case.codesnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDECodeSnippetCompletionPrefix 6 | clean-swift usecase 7 | IDECodeSnippetCompletionScopes 8 | 9 | ClassImplementation 10 | 11 | IDECodeSnippetContents 12 | struct <#Use Case#> { 13 | 14 | struct Request { 15 | 16 | } 17 | 18 | struct Response { 19 | 20 | } 21 | 22 | struct ViewModel { 23 | 24 | } 25 | } 26 | IDECodeSnippetIdentifier 27 | EE0E1F91-B40D-4ADD-8B2D-C44D2B7DC9C3 28 | IDECodeSnippetLanguage 29 | Xcode.SourceCodeLanguage.Swift 30 | IDECodeSnippetSummary 31 | Creates necessary models for a use case 32 | IDECodeSnippetTitle 33 | Clean Swift - Use Case Models 34 | IDECodeSnippetUserSnippet 35 | 36 | IDECodeSnippetVersion 37 | 2 38 | Author 39 | Miguel Berrocal (miguel@helm.cat) 40 | 41 | 42 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.1.2 -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #JesusCamacho 3 | 4 | view="UIViewController" 5 | table="UITableViewController" 6 | collection="UICollectionViewController" 7 | 8 | #Eliminamos directorios de Clean Swift HELM/Scene.xctemplate 9 | rm -rf Clean\ Swift\ HELM/Scene.xctemplate/$view 10 | rm -rf Clean\ Swift\ HELM/Scene.xctemplate/$table 11 | rm -rf Clean\ Swift\ HELM/Scene.xctemplate/$collection 12 | 13 | # Copiamos los tres directorios de View Controller.xctemplate a Scene.xctemplate 14 | cp -rf Clean\ Swift\ HELM/View\ Controller.xctemplate/$view Clean\ Swift\ HELM/Scene.xctemplate 15 | cp -rf Clean\ Swift\ HELM/View\ Controller.xctemplate/$table Clean\ Swift\ HELM/Scene.xctemplate 16 | cp -rf Clean\ Swift\ HELM/View\ Controller.xctemplate/$collection Clean\ Swift\ HELM/Scene.xctemplate 17 | 18 | # Copiamos los .swift dentro de $view, $table, $collection 19 | ## Configurator.xctemplate 20 | config="Configurator.xctemplate" 21 | configFile="___FILEBASENAME___Configurator.swift" 22 | cp Clean\ Swift\ HELM/$config/$configFile Clean\ Swift\ HELM/Scene.xctemplate/$view 23 | cp Clean\ Swift\ HELM/$config/$configFile Clean\ Swift\ HELM/Scene.xctemplate/$table 24 | cp Clean\ Swift\ HELM/$config/$configFile Clean\ Swift\ HELM/Scene.xctemplate/$collection 25 | 26 | ## Interactor.xctemplate 27 | int="Interactor.xctemplate" 28 | intFile="___FILEBASENAME___Interactor.swift" 29 | cp Clean\ Swift\ HELM/$int/$intFile Clean\ Swift\ HELM/Scene.xctemplate/$view 30 | cp Clean\ Swift\ HELM/$int/$intFile Clean\ Swift\ HELM/Scene.xctemplate/$table 31 | cp Clean\ Swift\ HELM/$int/$intFile Clean\ Swift\ HELM/Scene.xctemplate/$collection 32 | 33 | ## Models.xctemplate 34 | model="Models.xctemplate" 35 | modelFile="___FILEBASENAME___Models.swift" 36 | cp Clean\ Swift\ HELM/$model/$modelFile Clean\ Swift\ HELM/Scene.xctemplate/$view 37 | cp Clean\ Swift\ HELM/$model/$modelFile Clean\ Swift\ HELM/Scene.xctemplate/$table 38 | cp Clean\ Swift\ HELM/$model/$modelFile Clean\ Swift\ HELM/Scene.xctemplate/$collection 39 | 40 | ## Presenter.xctemplate 41 | pres="Presenter.xctemplate" 42 | presFile="___FILEBASENAME___Presenter.swift" 43 | cp Clean\ Swift\ HELM/$pres/$presFile Clean\ Swift\ HELM/Scene.xctemplate/$view 44 | cp Clean\ Swift\ HELM/$pres/$presFile Clean\ Swift\ HELM/Scene.xctemplate/$table 45 | cp Clean\ Swift\ HELM/$pres/$presFile Clean\ Swift\ HELM/Scene.xctemplate/$collection 46 | 47 | ## Router.xctemplate 48 | router="Router.xctemplate" 49 | routerFile="___FILEBASENAME___Router.swift" 50 | cp Clean\ Swift\ HELM/$router/$routerFile Clean\ Swift\ HELM/Scene.xctemplate/$view 51 | cp Clean\ Swift\ HELM/$router/$routerFile Clean\ Swift\ HELM/Scene.xctemplate/$table 52 | cp Clean\ Swift\ HELM/$router/$routerFile Clean\ Swift\ HELM/Scene.xctemplate/$collection 53 | 54 | 55 | --------------------------------------------------------------------------------