├── .gitignore ├── CoordinatorExample.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── CoordinatorExample ├── AppCoordinator.swift ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── LaunchScreen.storyboard ├── Coordinator.swift ├── DrinkTypeViewController.swift ├── Info.plist ├── NewOrderCoordinator.swift ├── RootViewCoordinator.swift ├── Services.swift ├── SnackTypeViewController.swift └── SplashViewController.swift └── README.md /.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 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/Preview.html 64 | fastlane/screenshots 65 | fastlane/test_output 66 | 67 | # Created by https://www.gitignore.io/api/node 68 | 69 | ### Node ### 70 | # Logs 71 | logs 72 | *.log 73 | npm-debug.log* 74 | 75 | # Runtime data 76 | pids 77 | *.pid 78 | *.seed 79 | *.pid.lock 80 | 81 | # Directory for instrumented libs generated by jscoverage/JSCover 82 | lib-cov 83 | 84 | # Coverage directory used by tools like istanbul 85 | coverage 86 | 87 | # nyc test coverage 88 | .nyc_output 89 | 90 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 91 | .grunt 92 | 93 | # node-waf configuration 94 | .lock-wscript 95 | 96 | # Compiled binary addons (http://nodejs.org/api/addons.html) 97 | build/Release 98 | 99 | # Dependency directories 100 | node_modules 101 | jspm_packages 102 | 103 | # Optional npm cache directory 104 | .npm 105 | 106 | # Optional REPL history 107 | .node_repl_history 108 | 109 | 110 | # questions output 111 | /questions/out 112 | .DS_Store 113 | -------------------------------------------------------------------------------- /CoordinatorExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BEEE17C61DD5CB2A004D6FCE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEE17C51DD5CB29004D6FCE /* AppDelegate.swift */; }; 11 | BEEE17CD1DD5CB2A004D6FCE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BEEE17CC1DD5CB2A004D6FCE /* Assets.xcassets */; }; 12 | BEEE17D01DD5CB2A004D6FCE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BEEE17CE1DD5CB2A004D6FCE /* LaunchScreen.storyboard */; }; 13 | BEEE17DA1DD5CB4B004D6FCE /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEE17D71DD5CB4B004D6FCE /* Coordinator.swift */; }; 14 | BEEE17DB1DD5CB4B004D6FCE /* RootViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEE17D81DD5CB4B004D6FCE /* RootViewCoordinator.swift */; }; 15 | BEEE17DC1DD5CB4B004D6FCE /* Services.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEE17D91DD5CB4B004D6FCE /* Services.swift */; }; 16 | BEEE17E01DD5CB51004D6FCE /* DrinkTypeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEE17DD1DD5CB50004D6FCE /* DrinkTypeViewController.swift */; }; 17 | BEEE17E11DD5CB51004D6FCE /* SnackTypeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEE17DE1DD5CB50004D6FCE /* SnackTypeViewController.swift */; }; 18 | BEEE17E21DD5CB51004D6FCE /* SplashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEE17DF1DD5CB50004D6FCE /* SplashViewController.swift */; }; 19 | BEEE17E81DD5CC76004D6FCE /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEE17E71DD5CC76004D6FCE /* AppCoordinator.swift */; }; 20 | BEEE17EA1DD5CC9C004D6FCE /* NewOrderCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEEE17E91DD5CC9C004D6FCE /* NewOrderCoordinator.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | BEEE17C21DD5CB29004D6FCE /* CoordinatorExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CoordinatorExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | BEEE17C51DD5CB29004D6FCE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 26 | BEEE17CC1DD5CB2A004D6FCE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 27 | BEEE17CF1DD5CB2A004D6FCE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 28 | BEEE17D11DD5CB2A004D6FCE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29 | BEEE17D71DD5CB4B004D6FCE /* Coordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = ""; }; 30 | BEEE17D81DD5CB4B004D6FCE /* RootViewCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootViewCoordinator.swift; sourceTree = ""; }; 31 | BEEE17D91DD5CB4B004D6FCE /* Services.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Services.swift; sourceTree = ""; }; 32 | BEEE17DD1DD5CB50004D6FCE /* DrinkTypeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrinkTypeViewController.swift; sourceTree = ""; }; 33 | BEEE17DE1DD5CB50004D6FCE /* SnackTypeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnackTypeViewController.swift; sourceTree = ""; }; 34 | BEEE17DF1DD5CB50004D6FCE /* SplashViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashViewController.swift; sourceTree = ""; }; 35 | BEEE17E71DD5CC76004D6FCE /* AppCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = ""; }; 36 | BEEE17E91DD5CC9C004D6FCE /* NewOrderCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewOrderCoordinator.swift; sourceTree = ""; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | BEEE17BF1DD5CB29004D6FCE /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | ); 45 | runOnlyForDeploymentPostprocessing = 0; 46 | }; 47 | /* End PBXFrameworksBuildPhase section */ 48 | 49 | /* Begin PBXGroup section */ 50 | BEEE17B91DD5CB29004D6FCE = { 51 | isa = PBXGroup; 52 | children = ( 53 | BEEE17C41DD5CB29004D6FCE /* CoordinatorExample */, 54 | BEEE17C31DD5CB29004D6FCE /* Products */, 55 | ); 56 | sourceTree = ""; 57 | }; 58 | BEEE17C31DD5CB29004D6FCE /* Products */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | BEEE17C21DD5CB29004D6FCE /* CoordinatorExample.app */, 62 | ); 63 | name = Products; 64 | sourceTree = ""; 65 | }; 66 | BEEE17C41DD5CB29004D6FCE /* CoordinatorExample */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | BEEE17E51DD5CBC9004D6FCE /* Core */, 70 | BEEE17E41DD5CBC3004D6FCE /* Coordinators */, 71 | BEEE17E31DD5CBB6004D6FCE /* View Controllers */, 72 | BEEE17E61DD5CC4C004D6FCE /* Other */, 73 | ); 74 | path = CoordinatorExample; 75 | sourceTree = ""; 76 | }; 77 | BEEE17E31DD5CBB6004D6FCE /* View Controllers */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | BEEE17DD1DD5CB50004D6FCE /* DrinkTypeViewController.swift */, 81 | BEEE17DE1DD5CB50004D6FCE /* SnackTypeViewController.swift */, 82 | BEEE17DF1DD5CB50004D6FCE /* SplashViewController.swift */, 83 | ); 84 | name = "View Controllers"; 85 | sourceTree = ""; 86 | }; 87 | BEEE17E41DD5CBC3004D6FCE /* Coordinators */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | BEEE17D71DD5CB4B004D6FCE /* Coordinator.swift */, 91 | BEEE17D81DD5CB4B004D6FCE /* RootViewCoordinator.swift */, 92 | BEEE17E71DD5CC76004D6FCE /* AppCoordinator.swift */, 93 | BEEE17E91DD5CC9C004D6FCE /* NewOrderCoordinator.swift */, 94 | ); 95 | name = Coordinators; 96 | sourceTree = ""; 97 | }; 98 | BEEE17E51DD5CBC9004D6FCE /* Core */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | BEEE17D91DD5CB4B004D6FCE /* Services.swift */, 102 | BEEE17C51DD5CB29004D6FCE /* AppDelegate.swift */, 103 | ); 104 | name = Core; 105 | sourceTree = ""; 106 | }; 107 | BEEE17E61DD5CC4C004D6FCE /* Other */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | BEEE17CC1DD5CB2A004D6FCE /* Assets.xcassets */, 111 | BEEE17CE1DD5CB2A004D6FCE /* LaunchScreen.storyboard */, 112 | BEEE17D11DD5CB2A004D6FCE /* Info.plist */, 113 | ); 114 | name = Other; 115 | sourceTree = ""; 116 | }; 117 | /* End PBXGroup section */ 118 | 119 | /* Begin PBXNativeTarget section */ 120 | BEEE17C11DD5CB29004D6FCE /* CoordinatorExample */ = { 121 | isa = PBXNativeTarget; 122 | buildConfigurationList = BEEE17D41DD5CB2A004D6FCE /* Build configuration list for PBXNativeTarget "CoordinatorExample" */; 123 | buildPhases = ( 124 | BEEE17BE1DD5CB29004D6FCE /* Sources */, 125 | BEEE17BF1DD5CB29004D6FCE /* Frameworks */, 126 | BEEE17C01DD5CB29004D6FCE /* Resources */, 127 | ); 128 | buildRules = ( 129 | ); 130 | dependencies = ( 131 | ); 132 | name = CoordinatorExample; 133 | productName = CoordinatorExample; 134 | productReference = BEEE17C21DD5CB29004D6FCE /* CoordinatorExample.app */; 135 | productType = "com.apple.product-type.application"; 136 | }; 137 | /* End PBXNativeTarget section */ 138 | 139 | /* Begin PBXProject section */ 140 | BEEE17BA1DD5CB29004D6FCE /* Project object */ = { 141 | isa = PBXProject; 142 | attributes = { 143 | LastSwiftUpdateCheck = 0800; 144 | LastUpgradeCheck = 0800; 145 | ORGANIZATIONNAME = "Will Townsend"; 146 | TargetAttributes = { 147 | BEEE17C11DD5CB29004D6FCE = { 148 | CreatedOnToolsVersion = 8.0; 149 | DevelopmentTeam = U4MT6NDQZ9; 150 | ProvisioningStyle = Automatic; 151 | }; 152 | }; 153 | }; 154 | buildConfigurationList = BEEE17BD1DD5CB29004D6FCE /* Build configuration list for PBXProject "CoordinatorExample" */; 155 | compatibilityVersion = "Xcode 3.2"; 156 | developmentRegion = English; 157 | hasScannedForEncodings = 0; 158 | knownRegions = ( 159 | en, 160 | Base, 161 | ); 162 | mainGroup = BEEE17B91DD5CB29004D6FCE; 163 | productRefGroup = BEEE17C31DD5CB29004D6FCE /* Products */; 164 | projectDirPath = ""; 165 | projectRoot = ""; 166 | targets = ( 167 | BEEE17C11DD5CB29004D6FCE /* CoordinatorExample */, 168 | ); 169 | }; 170 | /* End PBXProject section */ 171 | 172 | /* Begin PBXResourcesBuildPhase section */ 173 | BEEE17C01DD5CB29004D6FCE /* Resources */ = { 174 | isa = PBXResourcesBuildPhase; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | BEEE17D01DD5CB2A004D6FCE /* LaunchScreen.storyboard in Resources */, 178 | BEEE17CD1DD5CB2A004D6FCE /* Assets.xcassets in Resources */, 179 | ); 180 | runOnlyForDeploymentPostprocessing = 0; 181 | }; 182 | /* End PBXResourcesBuildPhase section */ 183 | 184 | /* Begin PBXSourcesBuildPhase section */ 185 | BEEE17BE1DD5CB29004D6FCE /* Sources */ = { 186 | isa = PBXSourcesBuildPhase; 187 | buildActionMask = 2147483647; 188 | files = ( 189 | BEEE17DC1DD5CB4B004D6FCE /* Services.swift in Sources */, 190 | BEEE17C61DD5CB2A004D6FCE /* AppDelegate.swift in Sources */, 191 | BEEE17E01DD5CB51004D6FCE /* DrinkTypeViewController.swift in Sources */, 192 | BEEE17E11DD5CB51004D6FCE /* SnackTypeViewController.swift in Sources */, 193 | BEEE17EA1DD5CC9C004D6FCE /* NewOrderCoordinator.swift in Sources */, 194 | BEEE17E81DD5CC76004D6FCE /* AppCoordinator.swift in Sources */, 195 | BEEE17DA1DD5CB4B004D6FCE /* Coordinator.swift in Sources */, 196 | BEEE17DB1DD5CB4B004D6FCE /* RootViewCoordinator.swift in Sources */, 197 | BEEE17E21DD5CB51004D6FCE /* SplashViewController.swift in Sources */, 198 | ); 199 | runOnlyForDeploymentPostprocessing = 0; 200 | }; 201 | /* End PBXSourcesBuildPhase section */ 202 | 203 | /* Begin PBXVariantGroup section */ 204 | BEEE17CE1DD5CB2A004D6FCE /* LaunchScreen.storyboard */ = { 205 | isa = PBXVariantGroup; 206 | children = ( 207 | BEEE17CF1DD5CB2A004D6FCE /* Base */, 208 | ); 209 | name = LaunchScreen.storyboard; 210 | sourceTree = ""; 211 | }; 212 | /* End PBXVariantGroup section */ 213 | 214 | /* Begin XCBuildConfiguration section */ 215 | BEEE17D21DD5CB2A004D6FCE /* Debug */ = { 216 | isa = XCBuildConfiguration; 217 | buildSettings = { 218 | ALWAYS_SEARCH_USER_PATHS = NO; 219 | CLANG_ANALYZER_NONNULL = YES; 220 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 221 | CLANG_CXX_LIBRARY = "libc++"; 222 | CLANG_ENABLE_MODULES = YES; 223 | CLANG_ENABLE_OBJC_ARC = YES; 224 | CLANG_WARN_BOOL_CONVERSION = YES; 225 | CLANG_WARN_CONSTANT_CONVERSION = YES; 226 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 227 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 228 | CLANG_WARN_EMPTY_BODY = YES; 229 | CLANG_WARN_ENUM_CONVERSION = YES; 230 | CLANG_WARN_INFINITE_RECURSION = YES; 231 | CLANG_WARN_INT_CONVERSION = YES; 232 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 233 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 234 | CLANG_WARN_UNREACHABLE_CODE = YES; 235 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 236 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 237 | COPY_PHASE_STRIP = NO; 238 | DEBUG_INFORMATION_FORMAT = dwarf; 239 | ENABLE_STRICT_OBJC_MSGSEND = YES; 240 | ENABLE_TESTABILITY = YES; 241 | GCC_C_LANGUAGE_STANDARD = gnu99; 242 | GCC_DYNAMIC_NO_PIC = NO; 243 | GCC_NO_COMMON_BLOCKS = YES; 244 | GCC_OPTIMIZATION_LEVEL = 0; 245 | GCC_PREPROCESSOR_DEFINITIONS = ( 246 | "DEBUG=1", 247 | "$(inherited)", 248 | ); 249 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 250 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 251 | GCC_WARN_UNDECLARED_SELECTOR = YES; 252 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 253 | GCC_WARN_UNUSED_FUNCTION = YES; 254 | GCC_WARN_UNUSED_VARIABLE = YES; 255 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 256 | MTL_ENABLE_DEBUG_INFO = YES; 257 | ONLY_ACTIVE_ARCH = YES; 258 | SDKROOT = iphoneos; 259 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 260 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 261 | }; 262 | name = Debug; 263 | }; 264 | BEEE17D31DD5CB2A004D6FCE /* Release */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | ALWAYS_SEARCH_USER_PATHS = NO; 268 | CLANG_ANALYZER_NONNULL = YES; 269 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 270 | CLANG_CXX_LIBRARY = "libc++"; 271 | CLANG_ENABLE_MODULES = YES; 272 | CLANG_ENABLE_OBJC_ARC = YES; 273 | CLANG_WARN_BOOL_CONVERSION = YES; 274 | CLANG_WARN_CONSTANT_CONVERSION = YES; 275 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 276 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 277 | CLANG_WARN_EMPTY_BODY = YES; 278 | CLANG_WARN_ENUM_CONVERSION = YES; 279 | CLANG_WARN_INFINITE_RECURSION = YES; 280 | CLANG_WARN_INT_CONVERSION = YES; 281 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 282 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 283 | CLANG_WARN_UNREACHABLE_CODE = YES; 284 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 285 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 286 | COPY_PHASE_STRIP = NO; 287 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 288 | ENABLE_NS_ASSERTIONS = NO; 289 | ENABLE_STRICT_OBJC_MSGSEND = YES; 290 | GCC_C_LANGUAGE_STANDARD = gnu99; 291 | GCC_NO_COMMON_BLOCKS = YES; 292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 294 | GCC_WARN_UNDECLARED_SELECTOR = YES; 295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 296 | GCC_WARN_UNUSED_FUNCTION = YES; 297 | GCC_WARN_UNUSED_VARIABLE = YES; 298 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 299 | MTL_ENABLE_DEBUG_INFO = NO; 300 | SDKROOT = iphoneos; 301 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 302 | VALIDATE_PRODUCT = YES; 303 | }; 304 | name = Release; 305 | }; 306 | BEEE17D51DD5CB2A004D6FCE /* Debug */ = { 307 | isa = XCBuildConfiguration; 308 | buildSettings = { 309 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 310 | DEVELOPMENT_TEAM = U4MT6NDQZ9; 311 | INFOPLIST_FILE = CoordinatorExample/Info.plist; 312 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 313 | PRODUCT_BUNDLE_IDENTIFIER = io.townsend.CoordinatorExample; 314 | PRODUCT_NAME = "$(TARGET_NAME)"; 315 | SWIFT_VERSION = 3.0; 316 | }; 317 | name = Debug; 318 | }; 319 | BEEE17D61DD5CB2A004D6FCE /* Release */ = { 320 | isa = XCBuildConfiguration; 321 | buildSettings = { 322 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 323 | DEVELOPMENT_TEAM = U4MT6NDQZ9; 324 | INFOPLIST_FILE = CoordinatorExample/Info.plist; 325 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 326 | PRODUCT_BUNDLE_IDENTIFIER = io.townsend.CoordinatorExample; 327 | PRODUCT_NAME = "$(TARGET_NAME)"; 328 | SWIFT_VERSION = 3.0; 329 | }; 330 | name = Release; 331 | }; 332 | /* End XCBuildConfiguration section */ 333 | 334 | /* Begin XCConfigurationList section */ 335 | BEEE17BD1DD5CB29004D6FCE /* Build configuration list for PBXProject "CoordinatorExample" */ = { 336 | isa = XCConfigurationList; 337 | buildConfigurations = ( 338 | BEEE17D21DD5CB2A004D6FCE /* Debug */, 339 | BEEE17D31DD5CB2A004D6FCE /* Release */, 340 | ); 341 | defaultConfigurationIsVisible = 0; 342 | defaultConfigurationName = Release; 343 | }; 344 | BEEE17D41DD5CB2A004D6FCE /* Build configuration list for PBXNativeTarget "CoordinatorExample" */ = { 345 | isa = XCConfigurationList; 346 | buildConfigurations = ( 347 | BEEE17D51DD5CB2A004D6FCE /* Debug */, 348 | BEEE17D61DD5CB2A004D6FCE /* Release */, 349 | ); 350 | defaultConfigurationIsVisible = 0; 351 | }; 352 | /* End XCConfigurationList section */ 353 | }; 354 | rootObject = BEEE17BA1DD5CB29004D6FCE /* Project object */; 355 | } 356 | -------------------------------------------------------------------------------- /CoordinatorExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CoordinatorExample/AppCoordinator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppCoordinator.swift 3 | // CoordinatorExample 4 | // 5 | // Created by Will Townsend on 11/11/16. 6 | // Copyright © 2016 Will Townsend. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | /// The AppCoordinator is our first coordinator 13 | /// In this example the AppCoordinator as a rootViewController 14 | class AppCoordinator: RootViewCoordinator { 15 | 16 | // MARK: - Properties 17 | 18 | let services: Services 19 | var childCoordinators: [Coordinator] = [] 20 | 21 | var rootViewController: UIViewController { 22 | return self.navigationController 23 | } 24 | 25 | /// Window to manage 26 | let window: UIWindow 27 | 28 | private lazy var navigationController: UINavigationController = { 29 | let navigationController = UINavigationController() 30 | navigationController.isNavigationBarHidden = true 31 | return navigationController 32 | }() 33 | 34 | // MARK: - Init 35 | 36 | public init(window: UIWindow, services: Services) { 37 | self.services = services 38 | self.window = window 39 | 40 | self.window.rootViewController = self.rootViewController 41 | self.window.makeKeyAndVisible() 42 | } 43 | 44 | // MARK: - Functions 45 | 46 | /// Starts the coordinator 47 | public func start() { 48 | self.showSplashViewController() 49 | } 50 | 51 | /// Creates a new SplashViewController and places it into the navigation controller 52 | private func showSplashViewController() { 53 | let splashViewController = SplashViewController(services: self.services) 54 | splashViewController.delegate = self 55 | self.navigationController.viewControllers = [splashViewController] 56 | } 57 | 58 | } 59 | 60 | // MARK: - SplashViewControllerDelegate 61 | 62 | extension AppCoordinator: SplashViewControllerDelegate { 63 | 64 | func splashViewControllerDidTapNewOrder(splashViewController: SplashViewController) { 65 | 66 | let newOrderCoordinator = NewOrderCoordinator(with: self.services) 67 | newOrderCoordinator.delegate = self 68 | newOrderCoordinator.start() 69 | self.addChildCoordinator(newOrderCoordinator) 70 | self.rootViewController.present(newOrderCoordinator.rootViewController, animated: true, completion: nil) 71 | } 72 | 73 | } 74 | 75 | // MARK: - NewOrderCoordinatorDelegate 76 | 77 | extension AppCoordinator: NewOrderCoordinatorDelegate { 78 | 79 | func newOrderCoordinatorDidRequestCancel(newOrderCoordinator: NewOrderCoordinator) { 80 | 81 | newOrderCoordinator.rootViewController.dismiss(animated: true) 82 | self.removeChildCoordinator(newOrderCoordinator) 83 | 84 | } 85 | 86 | func newOrderCoordinator(newOrderCoordinator: NewOrderCoordinator, didAddOrder orderPayload: NewOrderCoordinatorPayload) { 87 | 88 | guard let drinkType = orderPayload.selectedDrinkType, 89 | let snackType = orderPayload.selectedSnackType else { 90 | return 91 | } 92 | 93 | let order = Order(drinkType: drinkType, snackType: snackType) 94 | 95 | self.services.dataService.orders.append(order) 96 | 97 | newOrderCoordinator.rootViewController.dismiss(animated: true) 98 | self.removeChildCoordinator(newOrderCoordinator) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /CoordinatorExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // CoordinatorExample 4 | // 5 | // Created by Will Townsend on 11/11/16. 6 | // Copyright © 2016 Will Townsend. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | var appCoordinator: AppCoordinator! 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | 19 | self.window = UIWindow(frame: UIScreen.main.bounds) 20 | self.appCoordinator = AppCoordinator(window: self.window!, services: Services()) 21 | self.appCoordinator.start() 22 | 23 | return true 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /CoordinatorExample/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 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /CoordinatorExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /CoordinatorExample/Coordinator.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// The Coordinator protocol 4 | public protocol Coordinator: class { 5 | 6 | /// The services that the coordinator can use 7 | var services: Services { get } 8 | 9 | /// The array containing any child Coordinators 10 | var childCoordinators: [Coordinator] { get set } 11 | 12 | } 13 | 14 | public extension Coordinator { 15 | 16 | /// Add a child coordinator to the parent 17 | public func addChildCoordinator(_ childCoordinator: Coordinator) { 18 | self.childCoordinators.append(childCoordinator) 19 | } 20 | 21 | /// Remove a child coordinator from the parent 22 | public func removeChildCoordinator(_ childCoordinator: Coordinator) { 23 | self.childCoordinators = self.childCoordinators.filter { $0 !== childCoordinator } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /CoordinatorExample/DrinkTypeViewController.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import UIKit 3 | 4 | public protocol DrinkTypeControllerDelegate: class { 5 | func drinkTypeViewControllerDidTapClose(_ drinkTypeViewController: DrinkTypeViewController) 6 | func drinkTypeViewController(_ drinkTypeViewController: DrinkTypeViewController, didSelectDrinkType drinkType: String) 7 | } 8 | 9 | public class DrinkTypeViewController: UITableViewController { 10 | 11 | private let services: Services 12 | 13 | public weak var delegate: DrinkTypeControllerDelegate? 14 | 15 | lazy var closeBarButtonItem: UIBarButtonItem = { 16 | let closeBarButtonItem = UIBarButtonItem(title: "Close", style: .plain, target: self, action: #selector(self.closeButtonTapped)) 17 | return closeBarButtonItem 18 | }() 19 | 20 | private let drinkTypes = [ 21 | "Coffee", 22 | "Tea", 23 | "Flat white", 24 | "Coke" 25 | ] 26 | 27 | public init(services: Services) { 28 | self.services = services 29 | super.init(nibName: nil, bundle: nil) 30 | 31 | self.title = "Select Drink" 32 | self.navigationItem.leftBarButtonItem = self.closeBarButtonItem 33 | } 34 | 35 | @available(*, unavailable) 36 | required public init?(coder aDecoder: NSCoder) { 37 | fatalError("init(coder:) has not been implemented") 38 | } 39 | 40 | @objc private func closeButtonTapped(sender: UIBarButtonItem) { 41 | self.delegate?.drinkTypeViewControllerDidTapClose(self) 42 | } 43 | 44 | public override func viewDidLoad() { 45 | super.viewDidLoad() 46 | 47 | // I like slightly larger cells 😃 48 | self.tableView.rowHeight = 50 49 | } 50 | 51 | public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 52 | tableView.deselectRow(at: indexPath, animated: true) 53 | let drinkType = self.drinkTypes[indexPath.row] 54 | self.delegate?.drinkTypeViewController(self, didSelectDrinkType: drinkType) 55 | } 56 | 57 | public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 58 | 59 | let drinkType = self.drinkTypes[indexPath.row] 60 | 61 | let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: nil) 62 | cell.textLabel?.text = drinkType 63 | return cell 64 | } 65 | 66 | public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 67 | return self.drinkTypes.count 68 | } 69 | 70 | public override func numberOfSections(in tableView: UITableView) -> Int { 71 | return 1 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /CoordinatorExample/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 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /CoordinatorExample/NewOrderCoordinator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewOrderCoordinator.swift 3 | // CoordinatorExample 4 | // 5 | // Created by Will Townsend on 11/11/16. 6 | // Copyright © 2016 Will Townsend. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | protocol NewOrderCoordinatorDelegate: class { 13 | 14 | /// The user tapped the cancel button 15 | func newOrderCoordinatorDidRequestCancel(newOrderCoordinator: NewOrderCoordinator) 16 | 17 | /// The user completed the order flow with the payload 18 | func newOrderCoordinator(newOrderCoordinator: NewOrderCoordinator, didAddOrder orderPayload: NewOrderCoordinatorPayload) 19 | 20 | } 21 | 22 | class NewOrderCoordinatorPayload { 23 | var selectedDrinkType: String? 24 | var selectedSnackType: String? 25 | } 26 | 27 | class NewOrderCoordinator: RootViewCoordinator { 28 | 29 | // MARK: - Properties 30 | 31 | let services: Services 32 | var childCoordinators: [Coordinator] = [] 33 | 34 | var rootViewController: UIViewController { 35 | return self.navigationController 36 | } 37 | 38 | weak var delegate: NewOrderCoordinatorDelegate? 39 | 40 | var orderPayload: NewOrderCoordinatorPayload? 41 | 42 | private lazy var navigationController: UINavigationController = { 43 | let navigationController = UINavigationController() 44 | return navigationController 45 | }() 46 | 47 | // MARK: - Init 48 | 49 | init(with services: Services) { 50 | self.services = services 51 | } 52 | 53 | // MARK: - Functions 54 | 55 | func start() { 56 | let drinkTypeViewController = DrinkTypeViewController(services: self.services) 57 | drinkTypeViewController.delegate = self 58 | self.navigationController.viewControllers = [drinkTypeViewController] 59 | } 60 | 61 | func showSnackTypeViewController() { 62 | let snackTypeViewController = SnackTypeViewController(services: self.services) 63 | snackTypeViewController.delegate = self 64 | self.navigationController.pushViewController(snackTypeViewController, animated: true) 65 | } 66 | 67 | } 68 | 69 | // MARK: - DrinkTypeControllerDelegate 70 | 71 | extension NewOrderCoordinator: DrinkTypeControllerDelegate { 72 | 73 | func drinkTypeViewControllerDidTapClose(_ drinkTypeViewController: DrinkTypeViewController) { 74 | self.delegate?.newOrderCoordinatorDidRequestCancel(newOrderCoordinator: self) 75 | } 76 | 77 | func drinkTypeViewController(_ drinkTypeViewController: DrinkTypeViewController, didSelectDrinkType drinkType: String) { 78 | 79 | self.orderPayload = NewOrderCoordinatorPayload() 80 | self.orderPayload?.selectedDrinkType = drinkType 81 | 82 | self.showSnackTypeViewController() 83 | } 84 | 85 | } 86 | 87 | // MARK: - SnackTypeViewControllerDelegate 88 | 89 | extension NewOrderCoordinator: SnackTypeViewControllerDelegate { 90 | 91 | func snackTypeViewController(_ snackTypeViewController: SnackTypeViewController, didSelectSnackType snackType: String) { 92 | 93 | self.orderPayload?.selectedSnackType = snackType 94 | 95 | if let newOrderPayload = self.orderPayload { 96 | self.delegate?.newOrderCoordinator(newOrderCoordinator: self, didAddOrder: newOrderPayload) 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /CoordinatorExample/RootViewCoordinator.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import UIKit 3 | 4 | public protocol RootViewControllerProvider: class { 5 | // The coordinators 'rootViewController'. It helps to think of this as the view 6 | // controller that can be used to dismiss the coordinator from the view hierarchy. 7 | var rootViewController: UIViewController { get } 8 | } 9 | 10 | /// A Coordinator type that provides a root UIViewController 11 | public typealias RootViewCoordinator = Coordinator & RootViewControllerProvider 12 | -------------------------------------------------------------------------------- /CoordinatorExample/Services.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Services { 4 | 5 | public let dataService: DataService 6 | 7 | public init() { 8 | self.dataService = DataService() 9 | } 10 | } 11 | 12 | public struct Order { 13 | public let drinkType: String 14 | public let snackType: String 15 | 16 | public init(drinkType: String, snackType: String) { 17 | self.drinkType = drinkType 18 | self.snackType = snackType 19 | } 20 | 21 | } 22 | 23 | public class DataService { 24 | 25 | public var orders: [Order] = [] 26 | 27 | } 28 | -------------------------------------------------------------------------------- /CoordinatorExample/SnackTypeViewController.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import UIKit 3 | 4 | public protocol SnackTypeViewControllerDelegate: class { 5 | func snackTypeViewController(_ snackTypeViewController: SnackTypeViewController, didSelectSnackType snackType: String) 6 | } 7 | 8 | public class SnackTypeViewController: UITableViewController { 9 | 10 | private let services: Services 11 | 12 | public weak var delegate: SnackTypeViewControllerDelegate? 13 | 14 | private let snackTypes = [ 15 | "Muffin", 16 | "Cookie", 17 | "Tim tam", 18 | "Scroggin" 19 | ] 20 | 21 | public init(services: Services) { 22 | self.services = services 23 | super.init(nibName: nil, bundle: nil) 24 | 25 | self.title = "Select Snack" 26 | } 27 | 28 | @available(*, unavailable) 29 | required public init?(coder aDecoder: NSCoder) { 30 | fatalError("init(coder:) has not been implemented") 31 | } 32 | 33 | public override func viewDidLoad() { 34 | super.viewDidLoad() 35 | 36 | // I like slightly larger cells 😃 37 | self.tableView.rowHeight = 50 38 | } 39 | 40 | public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 41 | tableView.deselectRow(at: indexPath, animated: true) 42 | let snackType = self.snackTypes[indexPath.row] 43 | self.delegate?.snackTypeViewController(self, didSelectSnackType: snackType) 44 | } 45 | 46 | public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 47 | 48 | let snackType = self.snackTypes[indexPath.row] 49 | 50 | let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: nil) 51 | cell.textLabel?.text = snackType 52 | return cell 53 | } 54 | 55 | public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 56 | return self.snackTypes.count 57 | } 58 | 59 | public override func numberOfSections(in tableView: UITableView) -> Int { 60 | return 1 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /CoordinatorExample/SplashViewController.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import UIKit 3 | 4 | public protocol SplashViewControllerDelegate: class { 5 | func splashViewControllerDidTapNewOrder(splashViewController: SplashViewController) 6 | } 7 | 8 | public class SplashViewController: UIViewController { 9 | 10 | private let services: Services 11 | 12 | public weak var delegate: SplashViewControllerDelegate? 13 | 14 | private var titleLabel: UILabel = UILabel() 15 | 16 | public init(services: Services) { 17 | self.services = services 18 | super.init(nibName: nil, bundle: nil) 19 | } 20 | 21 | @available(*, unavailable) 22 | required public init?(coder aDecoder: NSCoder) { 23 | fatalError("init(coder:) has not been implemented") 24 | } 25 | 26 | override public func viewDidLoad() { 27 | super.viewDidLoad() 28 | 29 | self.view.backgroundColor = .white 30 | 31 | let newOrderButton = UIButton(type: .system) 32 | newOrderButton.setTitle("New order", for: .normal) 33 | newOrderButton.backgroundColor = .red 34 | newOrderButton.addTarget(self, action: #selector(didTapNewOrder), for: UIControlEvents.touchUpInside) 35 | 36 | self.view.addSubview(newOrderButton) 37 | 38 | newOrderButton.translatesAutoresizingMaskIntoConstraints = false 39 | newOrderButton.widthAnchor.constraint(equalToConstant: 260).isActive = true 40 | newOrderButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true 41 | newOrderButton.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor, constant: -20).isActive = true 42 | newOrderButton.heightAnchor.constraint(equalToConstant: 44).isActive = true 43 | 44 | self.titleLabel.numberOfLines = 0 45 | self.view.addSubview(self.titleLabel) 46 | 47 | self.titleLabel.translatesAutoresizingMaskIntoConstraints = false 48 | self.titleLabel.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true 49 | self.titleLabel.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 20).isActive = true 50 | 51 | self.updateView() 52 | 53 | } 54 | 55 | public override func viewWillAppear(_ animated: Bool) { 56 | super.viewWillAppear(animated) 57 | self.updateView() 58 | } 59 | 60 | private func updateView() { 61 | 62 | let orderCount = self.services.dataService.orders.count 63 | 64 | self.titleLabel.attributedText = self.attributedOrderString(orderCount: orderCount) 65 | } 66 | 67 | private func attributedOrderString(orderCount: Int) -> NSAttributedString { 68 | 69 | let paragraphStyle = NSMutableParagraphStyle() 70 | paragraphStyle.alignment = .center 71 | paragraphStyle.lineSpacing = 20 72 | 73 | let fontAttributes = [ 74 | NSForegroundColorAttributeName: UIColor.black, 75 | NSParagraphStyleAttributeName: paragraphStyle, 76 | NSFontAttributeName: UIFont.systemFont(ofSize: 40) 77 | ] 78 | 79 | let largeFontAttributes = [ 80 | NSForegroundColorAttributeName: UIColor.black, 81 | NSParagraphStyleAttributeName: paragraphStyle, 82 | NSFontAttributeName: UIFont.boldSystemFont(ofSize: 70) 83 | ] 84 | 85 | let string = NSMutableAttributedString() 86 | 87 | string.append(NSAttributedString(string: "Orders in Progress\n", attributes: fontAttributes)) 88 | 89 | 90 | string.append(NSAttributedString(string: "\(orderCount)", attributes: largeFontAttributes)) 91 | 92 | return string 93 | } 94 | 95 | @objc private func didTapNewOrder(sender: UIButton) { 96 | self.delegate?.splashViewControllerDidTapNewOrder(splashViewController: self) 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Coordinator Example 2 | 3 | This is the project to accompany my [blog post on the Coordinator Pattern](https://will.townsend.io/2016/an-ios-coordinator-pattern). 4 | 5 | ## 📍 Getting Started 6 | 7 | > As of 11th November 2016, this project requires [Xcode 8.0](https://developer.apple.com/xcode/downloads/) (Swift 3.0) 8 | 9 | The following commands will download the repository, and open the desired Xcode project. 10 | 11 | git clone git@github.com:wtsnz/Coordinator-Example.git 12 | cd Coordinator-Example 13 | open CoordinatorExample.xcodeproj 14 | 15 | --------------------------------------------------------------------------------