├── .gitignore ├── .swiftlint.yml ├── LICENSE ├── Podfile ├── Podfile.lock ├── Project.swift ├── README.md ├── Scripts ├── RSwiftRunScript.sh └── SwiftLintRunScript.sh ├── SwinjectReactorKitExample.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcshareddata │ └── xcschemes │ │ ├── SwinjectReactorKitExample.xcscheme │ │ ├── SwinjectReactorKitExampleTests.xcscheme │ │ └── SwinjectReactorKitExampleUITests.xcscheme └── xcuserdata │ └── hansangjin.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── SwinjectReactorKitExample.xcworkspace ├── .tuist-generated ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── xcschemes │ └── SwinjectReactorKitExample-Project.xcscheme ├── SwinjectReactorKitExample ├── Resources │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── initial_empty_image.imageset │ │ │ ├── Contents.json │ │ │ └── empty.png │ │ └── no_url_image.imageset │ │ │ ├── Contents.json │ │ │ └── empty2.png │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── indicator.json │ └── progress_bar.json ├── Sources │ ├── Application │ │ ├── AppDelegate.swift │ │ ├── DI │ │ │ └── DIContainer.swift │ │ └── SceneDelegate.swift │ ├── BusinessLayer │ │ └── Service │ │ │ ├── ImageService.swift │ │ │ └── SearchService.swift │ ├── DataLayer │ │ ├── Cache │ │ │ └── CacheStorage.swift │ │ ├── Model │ │ │ ├── Joke.swift │ │ │ └── User.swift │ │ └── Network │ │ │ ├── NetworkAPI.swift │ │ │ └── NetworkRepository.swift │ └── PresentationLayer │ │ └── Search │ │ ├── SearchReactor.swift │ │ └── SearchViewController.swift └── Supporting │ └── Info.plist ├── SwinjectReactorKitExampleTests ├── Info.plist ├── Mock │ ├── MockImageService.swift │ ├── MockNetworkRepository.swift │ ├── MockSearchService.swift │ └── MockURLSession.swift ├── PresentationTest │ └── SearchReactorTest.swift ├── RepositoryTest │ ├── NetworkRepositoryTest.swift │ └── URLSessionTest.swift └── ServiceTest │ ├── ImageServiceTest.swift │ └── SearchServiceTest.swift ├── SwinjectReactorKitExampleUITests ├── Info.plist └── SwinjectReactorKitExampleUITests.swift ├── Tuist ├── Config.swift └── ProjectDescriptionHelpers │ └── Project+Templates.swift └── project.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | 92 | ### Tuist derived files ### 93 | graph.dot 94 | Derived/ 95 | 96 | ### R 97 | 98 | R.generated.swift -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - file_length 3 | - trailing_whitespace 4 | - identifier_name 5 | - force_try 6 | - unused_closure_parameter 7 | 8 | included: 9 | - SwinjectReactorKitExample 10 | 11 | excluded: 12 | - Pods 13 | - SwinjectReactorKitExample/Resources/R.generated.swift 14 | #- BringChuChubaTests 15 | #- BringChuChubaUITests 16 | 17 | line_length: 110 18 | function_body_length: 100 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 SangJin Han 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | inhibit_all_warnings! 5 | 6 | target 'SwinjectReactorKitExample' do 7 | # Comment the next line if you don't want to use dynamic frameworks 8 | use_frameworks! 9 | 10 | # DI 11 | pod 'Swinject' 12 | pod 'SwinjectSafeAuto' 13 | # pod 'PureSwinject' 14 | 15 | # Architecture 16 | pod 'ReactorKit' 17 | 18 | # Reactive 19 | pod 'RxSwift' 20 | pod 'RxCocoa' 21 | 22 | # Util 23 | pod 'SnapKit' 24 | pod 'Then' 25 | 26 | # Resource 27 | pod 'R.swift' 28 | 29 | # UI 30 | pod 'lottie-ios' 31 | 32 | # Network 33 | pod 'Moya/RxSwift' 34 | 35 | # Pods for SwinjectReactorKitExample 36 | 37 | target 'SwinjectReactorKitExampleTests' do 38 | inherit! :search_paths 39 | 40 | # For Normal Test 41 | 42 | pod 'Quick' 43 | pod 'Nimble' 44 | 45 | # For Reactive Test 46 | 47 | pod 'RxTest' 48 | pod 'RxNimble' 49 | 50 | end 51 | 52 | target 'SwinjectReactorKitExampleUITests' do 53 | # Pods for testing 54 | end 55 | 56 | end 57 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (5.4.3) 3 | - lottie-ios (3.2.3) 4 | - Moya/Core (14.0.0): 5 | - Alamofire (~> 5.0) 6 | - Moya/RxSwift (14.0.0): 7 | - Moya/Core 8 | - RxSwift (~> 5.0) 9 | - Nimble (9.2.0) 10 | - Quick (4.0.0) 11 | - R.swift (5.4.0): 12 | - R.swift.Library (~> 5.3.0) 13 | - R.swift.Library (5.3.0) 14 | - ReactorKit (2.1.1): 15 | - RxSwift (~> 5.0) 16 | - WeakMapTable (~> 1.1) 17 | - RxBlocking (5.1.1): 18 | - RxSwift (~> 5) 19 | - RxCocoa (5.1.1): 20 | - RxRelay (~> 5) 21 | - RxSwift (~> 5) 22 | - RxNimble (5.0.0): 23 | - RxNimble/RxBlocking (= 5.0.0) 24 | - RxNimble/Core (5.0.0): 25 | - Nimble (~> 9.0) 26 | - RxSwift (~> 5.0) 27 | - RxNimble/RxBlocking (5.0.0): 28 | - RxBlocking 29 | - RxNimble/Core 30 | - RxRelay (5.1.1): 31 | - RxSwift (~> 5) 32 | - RxSwift (5.1.2) 33 | - RxTest (5.1.2): 34 | - RxSwift (~> 5) 35 | - SnapKit (5.0.1) 36 | - Swinject (2.7.1) 37 | - SwinjectSafeAuto (1.0.1): 38 | - Swinject (~> 2.6) 39 | - WeakMapTable (~> 1.0) 40 | - Then (2.7.0) 41 | - WeakMapTable (1.2.0) 42 | 43 | DEPENDENCIES: 44 | - lottie-ios 45 | - Moya/RxSwift 46 | - Nimble 47 | - Quick 48 | - R.swift 49 | - ReactorKit 50 | - RxCocoa 51 | - RxNimble 52 | - RxSwift 53 | - RxTest 54 | - SnapKit 55 | - Swinject 56 | - SwinjectSafeAuto 57 | - Then 58 | 59 | SPEC REPOS: 60 | trunk: 61 | - Alamofire 62 | - lottie-ios 63 | - Moya 64 | - Nimble 65 | - Quick 66 | - R.swift 67 | - R.swift.Library 68 | - ReactorKit 69 | - RxBlocking 70 | - RxCocoa 71 | - RxNimble 72 | - RxRelay 73 | - RxSwift 74 | - RxTest 75 | - SnapKit 76 | - Swinject 77 | - SwinjectSafeAuto 78 | - Then 79 | - WeakMapTable 80 | 81 | SPEC CHECKSUMS: 82 | Alamofire: e447a2774a40c996748296fa2c55112fdbbc42f9 83 | lottie-ios: c058aeafa76daa4cf64d773554bccc8385d0150e 84 | Moya: 5b45dacb75adb009f97fde91c204c1e565d31916 85 | Nimble: 4f4a345c80b503b3ea13606a4f98405974ee4d0b 86 | Quick: 6473349e43b9271a8d43839d9ba1c442ed1b7ac4 87 | R.swift: c533450b0f7dc494e0993f5f1a1db925d84c3006 88 | R.swift.Library: 0fc583cb55a99e28901299cc451614cad1161962 89 | ReactorKit: 6d894a20c3d508344320901cd8e386fde92df4b6 90 | RxBlocking: 5f700a78cad61ce253ebd37c9a39b5ccc76477b4 91 | RxCocoa: 32065309a38d29b5b0db858819b5bf9ef038b601 92 | RxNimble: 3b757b0f8fb4dc487c3f9a383bc61a6f5bd72d28 93 | RxRelay: d77f7d771495f43c556cbc43eebd1bb54d01e8e9 94 | RxSwift: 1e2e1f9570186967f617e49128ed26ccf1bafc8e 95 | RxTest: 274549b747dca56f47c52c8991ec5cf797ecfe40 96 | SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb 97 | Swinject: ddf78b8486dd9b71a667b852cad919ab4484478e 98 | SwinjectSafeAuto: 91266e1775ca6182f71b50e4f5e223e55a2b753c 99 | Then: acfe0be7e98221c6204e12f8161459606d5d822d 100 | WeakMapTable: 05c694ce8439a7a9ebabb56187287a63c57673d6 101 | 102 | PODFILE CHECKSUM: 129501af62dbec6224ca0b97ddf9973da5cfeec1 103 | 104 | COCOAPODS: 1.10.1 105 | -------------------------------------------------------------------------------- /Project.swift: -------------------------------------------------------------------------------- 1 | import ProjectDescription 2 | import ProjectDescriptionHelpers 3 | 4 | /* 5 | +-------------+ 6 | | | 7 | | App | Contains TuistSample App target and TuistSample unit-test target 8 | | | 9 | +------+-------------+-------+ 10 | | depends on | 11 | | | 12 | +----v-----+ +-----v-----+ 13 | | | | | 14 | | Kit | | UI | Two independent frameworks to share code and start modularising your app 15 | | | | | 16 | +----------+ +-----------+ 17 | 18 | */ 19 | 20 | 21 | let targetActions = [ 22 | TargetAction.pre( 23 | path: "Scripts/SwiftLintRunScript.sh", 24 | arguments: [], 25 | name: "SwiftLint" 26 | ), 27 | TargetAction.pre( 28 | path: "Scripts/RSwiftRunScript.sh", 29 | arguments: [], 30 | name: "R.swift", 31 | inputPaths: [Path.init("$TEMP_DIR/rswift-lastrun")], 32 | inputFileListPaths: [], 33 | outputPaths: [Path.init("$SRCROOT/SwinjectReactorKitExample/Resources/R.generated.swift")], 34 | outputFileListPaths: [] 35 | ) 36 | ] 37 | 38 | let targets = [ 39 | Target( 40 | name: "SwinjectReactorKitExample", 41 | platform: .iOS, 42 | product: .app, 43 | bundleId: "com.havi.SwinjectReactorKitExample", 44 | deploymentTarget: .iOS(targetVersion: "14.5", devices: [.iphone]), 45 | infoPlist: "SwinjectReactorKitExample/Supporting/Info.plist", 46 | sources: "SwinjectReactorKitExample/Sources/**", 47 | resources: "SwinjectReactorKitExample/Resources/**", 48 | actions: targetActions, 49 | dependencies: [ 50 | .cocoapods(path: ".") 51 | ] 52 | ), 53 | Target( 54 | name: "SwinjectReactorKitExampleTests", 55 | platform: .iOS, 56 | product: .unitTests, 57 | bundleId: "com.havi.SwinjectReactorKitExampleTests", 58 | infoPlist: "SwinjectReactorKitExampleTests/Info.plist", 59 | sources: "SwinjectReactorKitExampleTests/**", 60 | dependencies: [ 61 | .target(name: "SwinjectReactorKitExample") 62 | ] 63 | ), 64 | Target( 65 | name: "SwinjectReactorKitExampleUITests", 66 | platform: .iOS, 67 | product: .uiTests, 68 | bundleId: "com.havi.SwinjectReactorKitExampleUITests", 69 | infoPlist: "SwinjectReactorKitExampleTests/Info.plist", 70 | sources: "SwinjectReactorKitExampleUITests/**", 71 | dependencies: [ 72 | .target(name: "SwinjectReactorKitExample") 73 | ] 74 | ) 75 | ] 76 | 77 | // MARK: - Project 78 | 79 | // Creates our project using a helper function defined in ProjectDescriptionHelpers 80 | let project = Project( 81 | name: "SwinjectReactorKitExample", 82 | organizationName: "havi", 83 | targets: targets 84 | ) 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwinjectReactorKitExample 2 | 3 | This is a Demo App for `tuist`, `Swinject`, `Clean Architectue`, `ReactorKit` and `BDD` 4 | 5 | 이 프로젝트를 실행시켜보려면 `tuist`를 깔고, generate해야함 6 | 7 | 실행해도 별거는 없으니 코드만 보시는거 추천 드립니다! :) 8 | 9 | ![image](https://user-images.githubusercontent.com/57659933/122357398-af66fd00-cf8e-11eb-99fe-bcc5c5d0020f.png) 10 | 11 | # Goal 12 | 13 | 1. 테스트 가능한 코드 구현을 위한 리액터킷 구조의 예제 구현 14 | 2. Clean-Architecture 구조를 적용하여, Presentation Layer(뷰, 리액터), Business Layer(서비스), Core Layer(네트워크/데이터베이스, 엔티티) 분리 15 | 3. Quick, Nimble을 사용하여 테스트 코드 작성(BDD) 16 | 4. tuist를 활용한 프로젝트 관리 17 | 18 | # Contributor 19 | 20 | - [hansangjin96](https://github.com/hansangjin96) 21 | - [kyungpyoda](https://github.com/kyungpyoda) 22 | 23 | 24 | # Open Source 25 | 26 | ### Dependency Management 27 | 28 | - Swinject 29 | - SwinjectSafeAuto 30 | - PureSwinject 31 | 32 | ### Architecture 33 | 34 | - ReactorKit 35 | 36 | ### UI 37 | 38 | - RxSwift 39 | - RxCocoa 40 | - SnapKit 41 | - lottie-ios 42 | 43 | ### Util 44 | 45 | - Then 46 | 47 | ### Network 48 | 49 | - Moya/RxSwift 50 | 51 | ### Test 52 | 53 | - Quick 54 | - Nimble 55 | - RxTest 56 | - RxNimble 57 | 58 | # Requirements 59 | 60 | - Xcode 12.x 61 | - Swift 5.x 62 | 63 | # License 64 | 65 | - MIT License 66 | -------------------------------------------------------------------------------- /Scripts/RSwiftRunScript.sh: -------------------------------------------------------------------------------- 1 | "$PODS_ROOT/R.swift/rswift" generate "$SCRIPT_OUTPUT_FILE_0" 2 | 3 | #"$PODS_ROOT/R.swift/rswift" generate "$SRCROOT/SwinjectReactorKitExample/Resources/R.generated.swift" 4 | -------------------------------------------------------------------------------- /Scripts/SwiftLintRunScript.sh: -------------------------------------------------------------------------------- 1 | if which swiftlint > /dev/null; then 2 | swiftlint 3 | else 4 | echo "SwiftLint not installed?" 5 | fi -------------------------------------------------------------------------------- /SwinjectReactorKitExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 01D09A09D25E1DBD48867264 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 08123176A7BAA9F6A5BFFCB0 /* Assets.xcassets */; }; 11 | 02B15DE2CF6D68CF50259044 /* SearchService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D716BD140B2861B30B80642 /* SearchService.swift */; }; 12 | 0BE4741F3E700BBFDFF3E3EA /* Joke.swift in Sources */ = {isa = PBXBuildFile; fileRef = E412CEE621BA8CA0B8B01425 /* Joke.swift */; }; 13 | 0C5FBD1286DCFD4A0E2A9CA0 /* SearchReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 783C2F1309905ABBA2D469E1 /* SearchReactor.swift */; }; 14 | 114068827E0A2F2DE6E8EDBD /* MockURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6582312DC55849ABF116FD8E /* MockURLSession.swift */; }; 15 | 2AF9947C9FC4CA0D7CDFAE0E /* SearchServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDCE2BB475A917B8E740E20C /* SearchServiceTest.swift */; }; 16 | 34BA06E3B9E1862996A0C324 /* SwinjectReactorKitExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8C1AE167115DEEA96B3037F /* SwinjectReactorKitExampleUITests.swift */; }; 17 | 34D84F083BFF175DC13FF687 /* Assets+SwinjectReactorKitExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA5A36737E574ECF5D8EE79 /* Assets+SwinjectReactorKitExample.swift */; }; 18 | 408359EF26800C9100CE32C3 /* R.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 408359EE26800C9100CE32C3 /* R.generated.swift */; }; 19 | 627C1F24615FA8B65BBF283A /* Pods_SwinjectReactorKitExample_SwinjectReactorKitExampleUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9774AF909B381689A26876 /* Pods_SwinjectReactorKitExample_SwinjectReactorKitExampleUITests.framework */; }; 20 | 66C73856C055094A58993C4A /* ImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA822CB4BA620F3BC5A9CFD9 /* ImageService.swift */; }; 21 | 6829069CE43ABCFA111FBD89 /* indicator.json in Resources */ = {isa = PBXBuildFile; fileRef = 80EC3CD0DD9A2A1EB7082EA4 /* indicator.json */; }; 22 | 6B7F1352892B0CFF59D4367C /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9E6FA2A042BC6B994544BB /* User.swift */; }; 23 | 6CFB0D3925D0B22BEDDB0125 /* NetworkAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B857316DE9969988BB9F50 /* NetworkAPI.swift */; }; 24 | 72D8E5815D5AD7402220843D /* NetworkRepositoryTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68DD3869684CF377AB45CC6 /* NetworkRepositoryTest.swift */; }; 25 | 88B2CFEA412D5D06F59C24EC /* MockImageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1EDB8A998FB874CECD2D665 /* MockImageService.swift */; }; 26 | 9021DA2A5BBD32A35E4445D8 /* DIContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DCDB31264B38EE0DEE5098B /* DIContainer.swift */; }; 27 | 993607F35EF665D94F574559 /* NetworkRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADF1C2C5C216876D077445FD /* NetworkRepository.swift */; }; 28 | A65BF96B61DB58A33B3887D1 /* SearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B45D71B16C9FE3C4001D088 /* SearchViewController.swift */; }; 29 | AB032848534A961A4723F677 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F4996BF24A8D5D3FBC4C5B20 /* LaunchScreen.storyboard */; }; 30 | B0D3969BC84B2C744B0A552C /* Pods_SwinjectReactorKitExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 884DDDD43D5354F5522A8FF4 /* Pods_SwinjectReactorKitExample.framework */; }; 31 | B1DE27FF77CACB13AE27F956 /* Bundle+SwinjectReactorKitExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32771A268711827082D943EB /* Bundle+SwinjectReactorKitExample.swift */; }; 32 | B8F8EE6666B2454BD6057BD0 /* URLSessionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0349A52867A0463E287A94B2 /* URLSessionTest.swift */; }; 33 | BA8EC14809540431E5FB035C /* MockNetworkRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 742C88F56B57A083694AC588 /* MockNetworkRepository.swift */; }; 34 | BE06E67C962C366564594293 /* MockSearchService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 839989571A8087A03E64F745 /* MockSearchService.swift */; }; 35 | BEE617F4E2F4CF432CE95C09 /* CacheStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D82E01DB1A01AA2A49F431 /* CacheStorage.swift */; }; 36 | BF58FAB68BADFBDC6F11962A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C59EDFFA99B3768D124EE1E0 /* AppDelegate.swift */; }; 37 | CB3AA66AA5A284A5222FD6CB /* Pods_SwinjectReactorKitExampleTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E587AD492C0FB41CEBDD7D46 /* Pods_SwinjectReactorKitExampleTests.framework */; }; 38 | CC07D5D6A8AB8EDC1BA82B5D /* SearchReactorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 831E496A05B9362C2B7BAAB8 /* SearchReactorTest.swift */; }; 39 | D0913CD3895D0BCA9346EF4D /* progress_bar.json in Resources */ = {isa = PBXBuildFile; fileRef = FAE07F9ADCE5AD91720BDBBF /* progress_bar.json */; }; 40 | D5C2C3BFB566381A34D509D1 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9699DD48A9D7145F99D286 /* SceneDelegate.swift */; }; 41 | F57B80B57BC21BBC84158668 /* ImageServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC19008CD3D8DBDFE5EAACD /* ImageServiceTest.swift */; }; 42 | /* End PBXBuildFile section */ 43 | 44 | /* Begin PBXContainerItemProxy section */ 45 | 3C6DD1448E1252CAA0508C0A /* PBXContainerItemProxy */ = { 46 | isa = PBXContainerItemProxy; 47 | containerPortal = 12F2DC6F253DB0D10222AAA4 /* Project object */; 48 | proxyType = 1; 49 | remoteGlobalIDString = F48B8F3141E527587D1556AC; 50 | remoteInfo = SwinjectReactorKitExample; 51 | }; 52 | 53D4C9BF9DD7EEFCA9B40B6F /* PBXContainerItemProxy */ = { 53 | isa = PBXContainerItemProxy; 54 | containerPortal = 12F2DC6F253DB0D10222AAA4 /* Project object */; 55 | proxyType = 1; 56 | remoteGlobalIDString = F48B8F3141E527587D1556AC; 57 | remoteInfo = SwinjectReactorKitExample; 58 | }; 59 | /* End PBXContainerItemProxy section */ 60 | 61 | /* Begin PBXCopyFilesBuildPhase section */ 62 | 28DCC759070C040AE37DFB3C /* Embed Frameworks */ = { 63 | isa = PBXCopyFilesBuildPhase; 64 | buildActionMask = 2147483647; 65 | dstPath = ""; 66 | dstSubfolderSpec = 10; 67 | files = ( 68 | ); 69 | name = "Embed Frameworks"; 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | 799EF74B7EF44BFA12295015 /* Embed Frameworks */ = { 73 | isa = PBXCopyFilesBuildPhase; 74 | buildActionMask = 2147483647; 75 | dstPath = ""; 76 | dstSubfolderSpec = 10; 77 | files = ( 78 | ); 79 | name = "Embed Frameworks"; 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | C77F6AD1F1D1B6766B809C16 /* Embed Frameworks */ = { 83 | isa = PBXCopyFilesBuildPhase; 84 | buildActionMask = 2147483647; 85 | dstPath = ""; 86 | dstSubfolderSpec = 10; 87 | files = ( 88 | ); 89 | name = "Embed Frameworks"; 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | /* End PBXCopyFilesBuildPhase section */ 93 | 94 | /* Begin PBXFileReference section */ 95 | 01B857316DE9969988BB9F50 /* NetworkAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkAPI.swift; sourceTree = ""; }; 96 | 0349A52867A0463E287A94B2 /* URLSessionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionTest.swift; sourceTree = ""; }; 97 | 08123176A7BAA9F6A5BFFCB0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 98 | 0DCDB31264B38EE0DEE5098B /* DIContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DIContainer.swift; sourceTree = ""; }; 99 | 32771A268711827082D943EB /* Bundle+SwinjectReactorKitExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+SwinjectReactorKitExample.swift"; sourceTree = ""; }; 100 | 3D1EDA1D3F5F7EC2BAFC0B21 /* SwinjectReactorKitExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwinjectReactorKitExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 101 | 408359EE26800C9100CE32C3 /* R.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = R.generated.swift; sourceTree = ""; }; 102 | 49D82E01DB1A01AA2A49F431 /* CacheStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheStorage.swift; sourceTree = ""; }; 103 | 4D0DA6C26394EC7C58D9D60A /* SwinjectReactorKitExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwinjectReactorKitExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 104 | 5B45D71B16C9FE3C4001D088 /* SearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewController.swift; sourceTree = ""; }; 105 | 5BAB44F911707258AC1AB522 /* Pods-SwinjectReactorKitExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwinjectReactorKitExample.release.xcconfig"; path = "Target Support Files/Pods-SwinjectReactorKitExample/Pods-SwinjectReactorKitExample.release.xcconfig"; sourceTree = ""; }; 106 | 5D716BD140B2861B30B80642 /* SearchService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchService.swift; sourceTree = ""; }; 107 | 5E9774AF909B381689A26876 /* Pods_SwinjectReactorKitExample_SwinjectReactorKitExampleUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwinjectReactorKitExample_SwinjectReactorKitExampleUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 108 | 6582312DC55849ABF116FD8E /* MockURLSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockURLSession.swift; sourceTree = ""; }; 109 | 742C88F56B57A083694AC588 /* MockNetworkRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockNetworkRepository.swift; sourceTree = ""; }; 110 | 783C2F1309905ABBA2D469E1 /* SearchReactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchReactor.swift; sourceTree = ""; }; 111 | 80EC3CD0DD9A2A1EB7082EA4 /* indicator.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = indicator.json; sourceTree = ""; }; 112 | 831E496A05B9362C2B7BAAB8 /* SearchReactorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchReactorTest.swift; sourceTree = ""; }; 113 | 839989571A8087A03E64F745 /* MockSearchService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSearchService.swift; sourceTree = ""; }; 114 | 884DDDD43D5354F5522A8FF4 /* Pods_SwinjectReactorKitExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwinjectReactorKitExample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 115 | 9C4D9A81FBFBC1C2B8911240 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 116 | 9F37465FDCA7B00D00007DDE /* SwinjectReactorKitExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwinjectReactorKitExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 117 | A023A1A6FC82E2CBD03CA064 /* Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests.release.xcconfig"; path = "Target Support Files/Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests/Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests.release.xcconfig"; sourceTree = ""; }; 118 | AA2F42EAC242725F76825AA8 /* Pods-SwinjectReactorKitExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwinjectReactorKitExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-SwinjectReactorKitExampleTests/Pods-SwinjectReactorKitExampleTests.debug.xcconfig"; sourceTree = ""; }; 119 | AA9699DD48A9D7145F99D286 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 120 | ADF1C2C5C216876D077445FD /* NetworkRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkRepository.swift; sourceTree = ""; }; 121 | B1EDB8A998FB874CECD2D665 /* MockImageService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockImageService.swift; sourceTree = ""; }; 122 | B640595E0A7EEF5DD6EEBA9B /* Pods-SwinjectReactorKitExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwinjectReactorKitExample.debug.xcconfig"; path = "Target Support Files/Pods-SwinjectReactorKitExample/Pods-SwinjectReactorKitExample.debug.xcconfig"; sourceTree = ""; }; 123 | B68DD3869684CF377AB45CC6 /* NetworkRepositoryTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkRepositoryTest.swift; sourceTree = ""; }; 124 | BD9E6FA2A042BC6B994544BB /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; 125 | BDCE2BB475A917B8E740E20C /* SearchServiceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchServiceTest.swift; sourceTree = ""; }; 126 | BFC19008CD3D8DBDFE5EAACD /* ImageServiceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageServiceTest.swift; sourceTree = ""; }; 127 | C59EDFFA99B3768D124EE1E0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 128 | CA822CB4BA620F3BC5A9CFD9 /* ImageService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageService.swift; sourceTree = ""; }; 129 | CFC49AE8A66037B2C95EC069 /* Pods-SwinjectReactorKitExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwinjectReactorKitExampleTests.release.xcconfig"; path = "Target Support Files/Pods-SwinjectReactorKitExampleTests/Pods-SwinjectReactorKitExampleTests.release.xcconfig"; sourceTree = ""; }; 130 | E412CEE621BA8CA0B8B01425 /* Joke.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Joke.swift; sourceTree = ""; }; 131 | E587AD492C0FB41CEBDD7D46 /* Pods_SwinjectReactorKitExampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwinjectReactorKitExampleTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 132 | EAD0CD3BDD883CA0E03D2A5F /* Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests.debug.xcconfig"; path = "Target Support Files/Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests/Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests.debug.xcconfig"; sourceTree = ""; }; 133 | ED10E9E96EBAC820F5C69CB6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 134 | EDA5A36737E574ECF5D8EE79 /* Assets+SwinjectReactorKitExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Assets+SwinjectReactorKitExample.swift"; sourceTree = ""; }; 135 | F8C1AE167115DEEA96B3037F /* SwinjectReactorKitExampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwinjectReactorKitExampleUITests.swift; sourceTree = ""; }; 136 | FAE07F9ADCE5AD91720BDBBF /* progress_bar.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = progress_bar.json; sourceTree = ""; }; 137 | FCB858944199D7250ECDE4FD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 138 | /* End PBXFileReference section */ 139 | 140 | /* Begin PBXFrameworksBuildPhase section */ 141 | 3795CD352520ED711AC8975B /* Frameworks */ = { 142 | isa = PBXFrameworksBuildPhase; 143 | buildActionMask = 2147483647; 144 | files = ( 145 | CB3AA66AA5A284A5222FD6CB /* Pods_SwinjectReactorKitExampleTests.framework in Frameworks */, 146 | ); 147 | runOnlyForDeploymentPostprocessing = 0; 148 | }; 149 | EFD742D47418E55D94ED833A /* Frameworks */ = { 150 | isa = PBXFrameworksBuildPhase; 151 | buildActionMask = 2147483647; 152 | files = ( 153 | B0D3969BC84B2C744B0A552C /* Pods_SwinjectReactorKitExample.framework in Frameworks */, 154 | ); 155 | runOnlyForDeploymentPostprocessing = 0; 156 | }; 157 | FC29EDFC02ED4A3A900069E8 /* Frameworks */ = { 158 | isa = PBXFrameworksBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | 627C1F24615FA8B65BBF283A /* Pods_SwinjectReactorKitExample_SwinjectReactorKitExampleUITests.framework in Frameworks */, 162 | ); 163 | runOnlyForDeploymentPostprocessing = 0; 164 | }; 165 | /* End PBXFrameworksBuildPhase section */ 166 | 167 | /* Begin PBXGroup section */ 168 | 0432189E79FDD1FD84E8AC45 /* Project */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 2C11B4B54579E5077FA73D11 /* Derived */, 172 | DB499701E9B571A06AC88F73 /* SwinjectReactorKitExample */, 173 | 0BB1D2FDC213488A77158735 /* SwinjectReactorKitExampleTests */, 174 | F3388423FC10311DFCE2BFAC /* SwinjectReactorKitExampleUITests */, 175 | ); 176 | name = Project; 177 | sourceTree = ""; 178 | }; 179 | 0ACA11EE0E0CACA2CC9359B6 /* Frameworks */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | 884DDDD43D5354F5522A8FF4 /* Pods_SwinjectReactorKitExample.framework */, 183 | 5E9774AF909B381689A26876 /* Pods_SwinjectReactorKitExample_SwinjectReactorKitExampleUITests.framework */, 184 | E587AD492C0FB41CEBDD7D46 /* Pods_SwinjectReactorKitExampleTests.framework */, 185 | ); 186 | name = Frameworks; 187 | sourceTree = ""; 188 | }; 189 | 0BB1D2FDC213488A77158735 /* SwinjectReactorKitExampleTests */ = { 190 | isa = PBXGroup; 191 | children = ( 192 | 1D19B95887F986CB068270A3 /* Mock */, 193 | 241C4C0CE44D0035E083DA33 /* PresentationTest */, 194 | 6AD1648019E663C016FD6C4D /* RepositoryTest */, 195 | 94558CEBD7397B6CFD3F8DCC /* ServiceTest */, 196 | FCB858944199D7250ECDE4FD /* Info.plist */, 197 | ); 198 | path = SwinjectReactorKitExampleTests; 199 | sourceTree = ""; 200 | }; 201 | 1ADE098B693F96EB9B35B528 = { 202 | isa = PBXGroup; 203 | children = ( 204 | 0432189E79FDD1FD84E8AC45 /* Project */, 205 | 0ACA11EE0E0CACA2CC9359B6 /* Frameworks */, 206 | 43F87EFA0D767A06A995ABDD /* Products */, 207 | 3C436296D00AE35692589401 /* Pods */, 208 | ); 209 | sourceTree = ""; 210 | }; 211 | 1C6D171DD8A9E05B104F36E5 /* DI */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | 0DCDB31264B38EE0DEE5098B /* DIContainer.swift */, 215 | ); 216 | path = DI; 217 | sourceTree = ""; 218 | }; 219 | 1D19B95887F986CB068270A3 /* Mock */ = { 220 | isa = PBXGroup; 221 | children = ( 222 | B1EDB8A998FB874CECD2D665 /* MockImageService.swift */, 223 | 742C88F56B57A083694AC588 /* MockNetworkRepository.swift */, 224 | 839989571A8087A03E64F745 /* MockSearchService.swift */, 225 | 6582312DC55849ABF116FD8E /* MockURLSession.swift */, 226 | ); 227 | path = Mock; 228 | sourceTree = ""; 229 | }; 230 | 241C4C0CE44D0035E083DA33 /* PresentationTest */ = { 231 | isa = PBXGroup; 232 | children = ( 233 | 831E496A05B9362C2B7BAAB8 /* SearchReactorTest.swift */, 234 | ); 235 | path = PresentationTest; 236 | sourceTree = ""; 237 | }; 238 | 2613CAC334EF5324A2CDEC29 /* DataLayer */ = { 239 | isa = PBXGroup; 240 | children = ( 241 | B0F3D394AD8E2B482C82C2B6 /* Cache */, 242 | 98C16A7036FE2A2A3B24EDC7 /* Model */, 243 | C3D7D3598D44599CE43A1D27 /* Network */, 244 | ); 245 | path = DataLayer; 246 | sourceTree = ""; 247 | }; 248 | 2C11B4B54579E5077FA73D11 /* Derived */ = { 249 | isa = PBXGroup; 250 | children = ( 251 | 2FF3D7DEBFCB958513223C00 /* Sources */, 252 | ); 253 | path = Derived; 254 | sourceTree = ""; 255 | }; 256 | 2FF3D7DEBFCB958513223C00 /* Sources */ = { 257 | isa = PBXGroup; 258 | children = ( 259 | EDA5A36737E574ECF5D8EE79 /* Assets+SwinjectReactorKitExample.swift */, 260 | 32771A268711827082D943EB /* Bundle+SwinjectReactorKitExample.swift */, 261 | ); 262 | path = Sources; 263 | sourceTree = ""; 264 | }; 265 | 3C436296D00AE35692589401 /* Pods */ = { 266 | isa = PBXGroup; 267 | children = ( 268 | B640595E0A7EEF5DD6EEBA9B /* Pods-SwinjectReactorKitExample.debug.xcconfig */, 269 | 5BAB44F911707258AC1AB522 /* Pods-SwinjectReactorKitExample.release.xcconfig */, 270 | EAD0CD3BDD883CA0E03D2A5F /* Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests.debug.xcconfig */, 271 | A023A1A6FC82E2CBD03CA064 /* Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests.release.xcconfig */, 272 | AA2F42EAC242725F76825AA8 /* Pods-SwinjectReactorKitExampleTests.debug.xcconfig */, 273 | CFC49AE8A66037B2C95EC069 /* Pods-SwinjectReactorKitExampleTests.release.xcconfig */, 274 | ); 275 | path = Pods; 276 | sourceTree = ""; 277 | }; 278 | 43F87EFA0D767A06A995ABDD /* Products */ = { 279 | isa = PBXGroup; 280 | children = ( 281 | 9F37465FDCA7B00D00007DDE /* SwinjectReactorKitExample.app */, 282 | 3D1EDA1D3F5F7EC2BAFC0B21 /* SwinjectReactorKitExampleTests.xctest */, 283 | 4D0DA6C26394EC7C58D9D60A /* SwinjectReactorKitExampleUITests.xctest */, 284 | ); 285 | name = Products; 286 | sourceTree = ""; 287 | }; 288 | 49A1D5E9B1DBD1C1199193F7 /* PresentationLayer */ = { 289 | isa = PBXGroup; 290 | children = ( 291 | 55A25DB82DED69D678BF9767 /* Search */, 292 | ); 293 | path = PresentationLayer; 294 | sourceTree = ""; 295 | }; 296 | 55A25DB82DED69D678BF9767 /* Search */ = { 297 | isa = PBXGroup; 298 | children = ( 299 | 783C2F1309905ABBA2D469E1 /* SearchReactor.swift */, 300 | 5B45D71B16C9FE3C4001D088 /* SearchViewController.swift */, 301 | ); 302 | path = Search; 303 | sourceTree = ""; 304 | }; 305 | 6088BE39A762CE11DA0856C6 /* Resources */ = { 306 | isa = PBXGroup; 307 | children = ( 308 | 408359EE26800C9100CE32C3 /* R.generated.swift */, 309 | F4996BF24A8D5D3FBC4C5B20 /* LaunchScreen.storyboard */, 310 | 08123176A7BAA9F6A5BFFCB0 /* Assets.xcassets */, 311 | 80EC3CD0DD9A2A1EB7082EA4 /* indicator.json */, 312 | FAE07F9ADCE5AD91720BDBBF /* progress_bar.json */, 313 | ); 314 | path = Resources; 315 | sourceTree = ""; 316 | }; 317 | 6AD1648019E663C016FD6C4D /* RepositoryTest */ = { 318 | isa = PBXGroup; 319 | children = ( 320 | B68DD3869684CF377AB45CC6 /* NetworkRepositoryTest.swift */, 321 | 0349A52867A0463E287A94B2 /* URLSessionTest.swift */, 322 | ); 323 | path = RepositoryTest; 324 | sourceTree = ""; 325 | }; 326 | 94558CEBD7397B6CFD3F8DCC /* ServiceTest */ = { 327 | isa = PBXGroup; 328 | children = ( 329 | BFC19008CD3D8DBDFE5EAACD /* ImageServiceTest.swift */, 330 | BDCE2BB475A917B8E740E20C /* SearchServiceTest.swift */, 331 | ); 332 | path = ServiceTest; 333 | sourceTree = ""; 334 | }; 335 | 98C16A7036FE2A2A3B24EDC7 /* Model */ = { 336 | isa = PBXGroup; 337 | children = ( 338 | E412CEE621BA8CA0B8B01425 /* Joke.swift */, 339 | BD9E6FA2A042BC6B994544BB /* User.swift */, 340 | ); 341 | path = Model; 342 | sourceTree = ""; 343 | }; 344 | B0F3D394AD8E2B482C82C2B6 /* Cache */ = { 345 | isa = PBXGroup; 346 | children = ( 347 | 49D82E01DB1A01AA2A49F431 /* CacheStorage.swift */, 348 | ); 349 | path = Cache; 350 | sourceTree = ""; 351 | }; 352 | C14C9F7EC84EFC7B06FFF2D5 /* BusinessLayer */ = { 353 | isa = PBXGroup; 354 | children = ( 355 | EF4ABA0F3D0CE97EC234E8ED /* Service */, 356 | ); 357 | path = BusinessLayer; 358 | sourceTree = ""; 359 | }; 360 | C3D7D3598D44599CE43A1D27 /* Network */ = { 361 | isa = PBXGroup; 362 | children = ( 363 | 01B857316DE9969988BB9F50 /* NetworkAPI.swift */, 364 | ADF1C2C5C216876D077445FD /* NetworkRepository.swift */, 365 | ); 366 | path = Network; 367 | sourceTree = ""; 368 | }; 369 | D059EC7DAA7039034CBB59C3 /* Supporting */ = { 370 | isa = PBXGroup; 371 | children = ( 372 | ED10E9E96EBAC820F5C69CB6 /* Info.plist */, 373 | ); 374 | path = Supporting; 375 | sourceTree = ""; 376 | }; 377 | D4B9407F23AF949D09A879ED /* Application */ = { 378 | isa = PBXGroup; 379 | children = ( 380 | 1C6D171DD8A9E05B104F36E5 /* DI */, 381 | C59EDFFA99B3768D124EE1E0 /* AppDelegate.swift */, 382 | AA9699DD48A9D7145F99D286 /* SceneDelegate.swift */, 383 | ); 384 | path = Application; 385 | sourceTree = ""; 386 | }; 387 | DB499701E9B571A06AC88F73 /* SwinjectReactorKitExample */ = { 388 | isa = PBXGroup; 389 | children = ( 390 | 6088BE39A762CE11DA0856C6 /* Resources */, 391 | ED51C4B7E445B132D477CAD5 /* Sources */, 392 | D059EC7DAA7039034CBB59C3 /* Supporting */, 393 | ); 394 | path = SwinjectReactorKitExample; 395 | sourceTree = ""; 396 | }; 397 | ED51C4B7E445B132D477CAD5 /* Sources */ = { 398 | isa = PBXGroup; 399 | children = ( 400 | D4B9407F23AF949D09A879ED /* Application */, 401 | C14C9F7EC84EFC7B06FFF2D5 /* BusinessLayer */, 402 | 2613CAC334EF5324A2CDEC29 /* DataLayer */, 403 | 49A1D5E9B1DBD1C1199193F7 /* PresentationLayer */, 404 | ); 405 | path = Sources; 406 | sourceTree = ""; 407 | }; 408 | EF4ABA0F3D0CE97EC234E8ED /* Service */ = { 409 | isa = PBXGroup; 410 | children = ( 411 | CA822CB4BA620F3BC5A9CFD9 /* ImageService.swift */, 412 | 5D716BD140B2861B30B80642 /* SearchService.swift */, 413 | ); 414 | path = Service; 415 | sourceTree = ""; 416 | }; 417 | F3388423FC10311DFCE2BFAC /* SwinjectReactorKitExampleUITests */ = { 418 | isa = PBXGroup; 419 | children = ( 420 | F8C1AE167115DEEA96B3037F /* SwinjectReactorKitExampleUITests.swift */, 421 | ); 422 | path = SwinjectReactorKitExampleUITests; 423 | sourceTree = ""; 424 | }; 425 | /* End PBXGroup section */ 426 | 427 | /* Begin PBXNativeTarget section */ 428 | 9B14BCD487BD843DDA349AA9 /* SwinjectReactorKitExampleTests */ = { 429 | isa = PBXNativeTarget; 430 | buildConfigurationList = 8D0A3F77323229E38026000F /* Build configuration list for PBXNativeTarget "SwinjectReactorKitExampleTests" */; 431 | buildPhases = ( 432 | FF28BA4F59A9F3DB1EC829B1 /* [CP] Check Pods Manifest.lock */, 433 | 2356FFAF5C1E4378FE7FE949 /* Sources */, 434 | F6C99FA9AA5AADA2077F1255 /* Resources */, 435 | A755AB9CC0D0EAC479965886 /* Embed Precompiled Frameworks */, 436 | C77F6AD1F1D1B6766B809C16 /* Embed Frameworks */, 437 | 3795CD352520ED711AC8975B /* Frameworks */, 438 | EF3292258978B5E3B0A2B2E0 /* [CP] Embed Pods Frameworks */, 439 | ); 440 | buildRules = ( 441 | ); 442 | dependencies = ( 443 | CF87BE6DF2B6CDEAEAB878C8 /* PBXTargetDependency */, 444 | ); 445 | name = SwinjectReactorKitExampleTests; 446 | productName = SwinjectReactorKitExampleTests; 447 | productReference = 3D1EDA1D3F5F7EC2BAFC0B21 /* SwinjectReactorKitExampleTests.xctest */; 448 | productType = "com.apple.product-type.bundle.unit-test"; 449 | }; 450 | A65E2F2080CA9E0975B426AD /* SwinjectReactorKitExampleUITests */ = { 451 | isa = PBXNativeTarget; 452 | buildConfigurationList = 10D04FF028D4CE3A170429CA /* Build configuration list for PBXNativeTarget "SwinjectReactorKitExampleUITests" */; 453 | buildPhases = ( 454 | 8FA2EF7AB54570929CEA3A82 /* [CP] Check Pods Manifest.lock */, 455 | F52EC0FF9FE6739D99A638CF /* Sources */, 456 | 184A414A5B04FF82526BA6CA /* Resources */, 457 | 5AAB910608A6FBA68468AE35 /* Embed Precompiled Frameworks */, 458 | 799EF74B7EF44BFA12295015 /* Embed Frameworks */, 459 | FC29EDFC02ED4A3A900069E8 /* Frameworks */, 460 | 2DB0348353CFA40627E0DA62 /* [CP] Embed Pods Frameworks */, 461 | ); 462 | buildRules = ( 463 | ); 464 | dependencies = ( 465 | 3AD916CE68B7707309E49AF7 /* PBXTargetDependency */, 466 | ); 467 | name = SwinjectReactorKitExampleUITests; 468 | productName = SwinjectReactorKitExampleUITests; 469 | productReference = 4D0DA6C26394EC7C58D9D60A /* SwinjectReactorKitExampleUITests.xctest */; 470 | productType = "com.apple.product-type.bundle.ui-testing"; 471 | }; 472 | F48B8F3141E527587D1556AC /* SwinjectReactorKitExample */ = { 473 | isa = PBXNativeTarget; 474 | buildConfigurationList = FC104E555942D7946BDCB21E /* Build configuration list for PBXNativeTarget "SwinjectReactorKitExample" */; 475 | buildPhases = ( 476 | 5743E21C987F0BFB79BDA3E8 /* [CP] Check Pods Manifest.lock */, 477 | A002E8E3B1A93673C794B89D /* SwiftLint */, 478 | 5B9314D4D1333EC805C35996 /* R.swift */, 479 | F08B1317C640BC7A40505864 /* Sources */, 480 | 32A11838FCA4AC0CB4B73111 /* Resources */, 481 | 0940C034590664F677686180 /* Embed Precompiled Frameworks */, 482 | 28DCC759070C040AE37DFB3C /* Embed Frameworks */, 483 | EFD742D47418E55D94ED833A /* Frameworks */, 484 | AF192DFD8EB6D12C061AAA7B /* [CP] Embed Pods Frameworks */, 485 | ); 486 | buildRules = ( 487 | ); 488 | dependencies = ( 489 | ); 490 | name = SwinjectReactorKitExample; 491 | productName = SwinjectReactorKitExample; 492 | productReference = 9F37465FDCA7B00D00007DDE /* SwinjectReactorKitExample.app */; 493 | productType = "com.apple.product-type.application"; 494 | }; 495 | /* End PBXNativeTarget section */ 496 | 497 | /* Begin PBXProject section */ 498 | 12F2DC6F253DB0D10222AAA4 /* Project object */ = { 499 | isa = PBXProject; 500 | attributes = { 501 | ORGANIZATIONNAME = havi; 502 | TargetAttributes = { 503 | 9B14BCD487BD843DDA349AA9 = { 504 | TestTargetID = F48B8F3141E527587D1556AC; 505 | }; 506 | A65E2F2080CA9E0975B426AD = { 507 | TestTargetID = F48B8F3141E527587D1556AC; 508 | }; 509 | }; 510 | }; 511 | buildConfigurationList = E60175D7B8BB9AB54CAD49F6 /* Build configuration list for PBXProject "SwinjectReactorKitExample" */; 512 | compatibilityVersion = "Xcode 9.3"; 513 | developmentRegion = en; 514 | hasScannedForEncodings = 0; 515 | knownRegions = ( 516 | Base, 517 | en, 518 | ); 519 | mainGroup = 1ADE098B693F96EB9B35B528; 520 | productRefGroup = 43F87EFA0D767A06A995ABDD /* Products */; 521 | projectDirPath = ""; 522 | projectRoot = ""; 523 | targets = ( 524 | F48B8F3141E527587D1556AC /* SwinjectReactorKitExample */, 525 | 9B14BCD487BD843DDA349AA9 /* SwinjectReactorKitExampleTests */, 526 | A65E2F2080CA9E0975B426AD /* SwinjectReactorKitExampleUITests */, 527 | ); 528 | }; 529 | /* End PBXProject section */ 530 | 531 | /* Begin PBXResourcesBuildPhase section */ 532 | 184A414A5B04FF82526BA6CA /* Resources */ = { 533 | isa = PBXResourcesBuildPhase; 534 | buildActionMask = 2147483647; 535 | files = ( 536 | ); 537 | runOnlyForDeploymentPostprocessing = 0; 538 | }; 539 | 32A11838FCA4AC0CB4B73111 /* Resources */ = { 540 | isa = PBXResourcesBuildPhase; 541 | buildActionMask = 2147483647; 542 | files = ( 543 | 01D09A09D25E1DBD48867264 /* Assets.xcassets in Resources */, 544 | AB032848534A961A4723F677 /* LaunchScreen.storyboard in Resources */, 545 | 6829069CE43ABCFA111FBD89 /* indicator.json in Resources */, 546 | D0913CD3895D0BCA9346EF4D /* progress_bar.json in Resources */, 547 | ); 548 | runOnlyForDeploymentPostprocessing = 0; 549 | }; 550 | F6C99FA9AA5AADA2077F1255 /* Resources */ = { 551 | isa = PBXResourcesBuildPhase; 552 | buildActionMask = 2147483647; 553 | files = ( 554 | ); 555 | runOnlyForDeploymentPostprocessing = 0; 556 | }; 557 | /* End PBXResourcesBuildPhase section */ 558 | 559 | /* Begin PBXShellScriptBuildPhase section */ 560 | 0940C034590664F677686180 /* Embed Precompiled Frameworks */ = { 561 | isa = PBXShellScriptBuildPhase; 562 | buildActionMask = 2147483647; 563 | files = ( 564 | ); 565 | inputPaths = ( 566 | ); 567 | name = "Embed Precompiled Frameworks"; 568 | outputPaths = ( 569 | ); 570 | runOnlyForDeploymentPostprocessing = 0; 571 | shellPath = /bin/sh; 572 | shellScript = "echo \"Skipping, nothing to be embedded.\""; 573 | }; 574 | 2DB0348353CFA40627E0DA62 /* [CP] Embed Pods Frameworks */ = { 575 | isa = PBXShellScriptBuildPhase; 576 | buildActionMask = 2147483647; 577 | files = ( 578 | ); 579 | inputFileListPaths = ( 580 | "${PODS_ROOT}/Target Support Files/Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests/Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist", 581 | ); 582 | name = "[CP] Embed Pods Frameworks"; 583 | outputFileListPaths = ( 584 | "${PODS_ROOT}/Target Support Files/Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests/Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist", 585 | ); 586 | runOnlyForDeploymentPostprocessing = 0; 587 | shellPath = /bin/sh; 588 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests/Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests-frameworks.sh\"\n"; 589 | showEnvVarsInLog = 0; 590 | }; 591 | 5743E21C987F0BFB79BDA3E8 /* [CP] Check Pods Manifest.lock */ = { 592 | isa = PBXShellScriptBuildPhase; 593 | buildActionMask = 2147483647; 594 | files = ( 595 | ); 596 | inputFileListPaths = ( 597 | ); 598 | inputPaths = ( 599 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 600 | "${PODS_ROOT}/Manifest.lock", 601 | ); 602 | name = "[CP] Check Pods Manifest.lock"; 603 | outputFileListPaths = ( 604 | ); 605 | outputPaths = ( 606 | "$(DERIVED_FILE_DIR)/Pods-SwinjectReactorKitExample-checkManifestLockResult.txt", 607 | ); 608 | runOnlyForDeploymentPostprocessing = 0; 609 | shellPath = /bin/sh; 610 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 611 | showEnvVarsInLog = 0; 612 | }; 613 | 5AAB910608A6FBA68468AE35 /* Embed Precompiled Frameworks */ = { 614 | isa = PBXShellScriptBuildPhase; 615 | buildActionMask = 2147483647; 616 | files = ( 617 | ); 618 | inputPaths = ( 619 | ); 620 | name = "Embed Precompiled Frameworks"; 621 | outputPaths = ( 622 | ); 623 | runOnlyForDeploymentPostprocessing = 0; 624 | shellPath = /bin/sh; 625 | shellScript = "echo \"Skipping, nothing to be embedded.\""; 626 | }; 627 | 5B9314D4D1333EC805C35996 /* R.swift */ = { 628 | isa = PBXShellScriptBuildPhase; 629 | buildActionMask = 2147483647; 630 | files = ( 631 | ); 632 | inputFileListPaths = ( 633 | ); 634 | inputPaths = ( 635 | "$TEMP_DIR/rswift-lastrun", 636 | ); 637 | name = R.swift; 638 | outputFileListPaths = ( 639 | ); 640 | outputPaths = ( 641 | $SRCROOT/SwinjectReactorKitExample/Resources/R.generated.swift, 642 | ); 643 | runOnlyForDeploymentPostprocessing = 0; 644 | shellPath = /bin/sh; 645 | shellScript = "\"$SRCROOT\"/Scripts/RSwiftRunScript.sh "; 646 | }; 647 | 8FA2EF7AB54570929CEA3A82 /* [CP] Check Pods Manifest.lock */ = { 648 | isa = PBXShellScriptBuildPhase; 649 | buildActionMask = 2147483647; 650 | files = ( 651 | ); 652 | inputFileListPaths = ( 653 | ); 654 | inputPaths = ( 655 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 656 | "${PODS_ROOT}/Manifest.lock", 657 | ); 658 | name = "[CP] Check Pods Manifest.lock"; 659 | outputFileListPaths = ( 660 | ); 661 | outputPaths = ( 662 | "$(DERIVED_FILE_DIR)/Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests-checkManifestLockResult.txt", 663 | ); 664 | runOnlyForDeploymentPostprocessing = 0; 665 | shellPath = /bin/sh; 666 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 667 | showEnvVarsInLog = 0; 668 | }; 669 | A002E8E3B1A93673C794B89D /* SwiftLint */ = { 670 | isa = PBXShellScriptBuildPhase; 671 | buildActionMask = 2147483647; 672 | files = ( 673 | ); 674 | inputFileListPaths = ( 675 | ); 676 | inputPaths = ( 677 | ); 678 | name = SwiftLint; 679 | outputFileListPaths = ( 680 | ); 681 | outputPaths = ( 682 | ); 683 | runOnlyForDeploymentPostprocessing = 0; 684 | shellPath = /bin/sh; 685 | shellScript = "\"$SRCROOT\"/Scripts/SwiftLintRunScript.sh "; 686 | }; 687 | A755AB9CC0D0EAC479965886 /* Embed Precompiled Frameworks */ = { 688 | isa = PBXShellScriptBuildPhase; 689 | buildActionMask = 2147483647; 690 | files = ( 691 | ); 692 | inputPaths = ( 693 | ); 694 | name = "Embed Precompiled Frameworks"; 695 | outputPaths = ( 696 | ); 697 | runOnlyForDeploymentPostprocessing = 0; 698 | shellPath = /bin/sh; 699 | shellScript = "echo \"Skipping, nothing to be embedded.\""; 700 | }; 701 | AF192DFD8EB6D12C061AAA7B /* [CP] Embed Pods Frameworks */ = { 702 | isa = PBXShellScriptBuildPhase; 703 | buildActionMask = 2147483647; 704 | files = ( 705 | ); 706 | inputFileListPaths = ( 707 | "${PODS_ROOT}/Target Support Files/Pods-SwinjectReactorKitExample/Pods-SwinjectReactorKitExample-frameworks-${CONFIGURATION}-input-files.xcfilelist", 708 | ); 709 | name = "[CP] Embed Pods Frameworks"; 710 | outputFileListPaths = ( 711 | "${PODS_ROOT}/Target Support Files/Pods-SwinjectReactorKitExample/Pods-SwinjectReactorKitExample-frameworks-${CONFIGURATION}-output-files.xcfilelist", 712 | ); 713 | runOnlyForDeploymentPostprocessing = 0; 714 | shellPath = /bin/sh; 715 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SwinjectReactorKitExample/Pods-SwinjectReactorKitExample-frameworks.sh\"\n"; 716 | showEnvVarsInLog = 0; 717 | }; 718 | EF3292258978B5E3B0A2B2E0 /* [CP] Embed Pods Frameworks */ = { 719 | isa = PBXShellScriptBuildPhase; 720 | buildActionMask = 2147483647; 721 | files = ( 722 | ); 723 | inputFileListPaths = ( 724 | "${PODS_ROOT}/Target Support Files/Pods-SwinjectReactorKitExampleTests/Pods-SwinjectReactorKitExampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", 725 | ); 726 | name = "[CP] Embed Pods Frameworks"; 727 | outputFileListPaths = ( 728 | "${PODS_ROOT}/Target Support Files/Pods-SwinjectReactorKitExampleTests/Pods-SwinjectReactorKitExampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", 729 | ); 730 | runOnlyForDeploymentPostprocessing = 0; 731 | shellPath = /bin/sh; 732 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SwinjectReactorKitExampleTests/Pods-SwinjectReactorKitExampleTests-frameworks.sh\"\n"; 733 | showEnvVarsInLog = 0; 734 | }; 735 | FF28BA4F59A9F3DB1EC829B1 /* [CP] Check Pods Manifest.lock */ = { 736 | isa = PBXShellScriptBuildPhase; 737 | buildActionMask = 2147483647; 738 | files = ( 739 | ); 740 | inputFileListPaths = ( 741 | ); 742 | inputPaths = ( 743 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 744 | "${PODS_ROOT}/Manifest.lock", 745 | ); 746 | name = "[CP] Check Pods Manifest.lock"; 747 | outputFileListPaths = ( 748 | ); 749 | outputPaths = ( 750 | "$(DERIVED_FILE_DIR)/Pods-SwinjectReactorKitExampleTests-checkManifestLockResult.txt", 751 | ); 752 | runOnlyForDeploymentPostprocessing = 0; 753 | shellPath = /bin/sh; 754 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 755 | showEnvVarsInLog = 0; 756 | }; 757 | /* End PBXShellScriptBuildPhase section */ 758 | 759 | /* Begin PBXSourcesBuildPhase section */ 760 | 2356FFAF5C1E4378FE7FE949 /* Sources */ = { 761 | isa = PBXSourcesBuildPhase; 762 | buildActionMask = 2147483647; 763 | files = ( 764 | 88B2CFEA412D5D06F59C24EC /* MockImageService.swift in Sources */, 765 | BA8EC14809540431E5FB035C /* MockNetworkRepository.swift in Sources */, 766 | BE06E67C962C366564594293 /* MockSearchService.swift in Sources */, 767 | 114068827E0A2F2DE6E8EDBD /* MockURLSession.swift in Sources */, 768 | CC07D5D6A8AB8EDC1BA82B5D /* SearchReactorTest.swift in Sources */, 769 | 72D8E5815D5AD7402220843D /* NetworkRepositoryTest.swift in Sources */, 770 | B8F8EE6666B2454BD6057BD0 /* URLSessionTest.swift in Sources */, 771 | F57B80B57BC21BBC84158668 /* ImageServiceTest.swift in Sources */, 772 | 2AF9947C9FC4CA0D7CDFAE0E /* SearchServiceTest.swift in Sources */, 773 | ); 774 | runOnlyForDeploymentPostprocessing = 0; 775 | }; 776 | F08B1317C640BC7A40505864 /* Sources */ = { 777 | isa = PBXSourcesBuildPhase; 778 | buildActionMask = 2147483647; 779 | files = ( 780 | 34D84F083BFF175DC13FF687 /* Assets+SwinjectReactorKitExample.swift in Sources */, 781 | B1DE27FF77CACB13AE27F956 /* Bundle+SwinjectReactorKitExample.swift in Sources */, 782 | 408359EF26800C9100CE32C3 /* R.generated.swift in Sources */, 783 | BF58FAB68BADFBDC6F11962A /* AppDelegate.swift in Sources */, 784 | 9021DA2A5BBD32A35E4445D8 /* DIContainer.swift in Sources */, 785 | D5C2C3BFB566381A34D509D1 /* SceneDelegate.swift in Sources */, 786 | 66C73856C055094A58993C4A /* ImageService.swift in Sources */, 787 | 02B15DE2CF6D68CF50259044 /* SearchService.swift in Sources */, 788 | BEE617F4E2F4CF432CE95C09 /* CacheStorage.swift in Sources */, 789 | 0BE4741F3E700BBFDFF3E3EA /* Joke.swift in Sources */, 790 | 6B7F1352892B0CFF59D4367C /* User.swift in Sources */, 791 | 6CFB0D3925D0B22BEDDB0125 /* NetworkAPI.swift in Sources */, 792 | 993607F35EF665D94F574559 /* NetworkRepository.swift in Sources */, 793 | 0C5FBD1286DCFD4A0E2A9CA0 /* SearchReactor.swift in Sources */, 794 | A65BF96B61DB58A33B3887D1 /* SearchViewController.swift in Sources */, 795 | ); 796 | runOnlyForDeploymentPostprocessing = 0; 797 | }; 798 | F52EC0FF9FE6739D99A638CF /* Sources */ = { 799 | isa = PBXSourcesBuildPhase; 800 | buildActionMask = 2147483647; 801 | files = ( 802 | 34BA06E3B9E1862996A0C324 /* SwinjectReactorKitExampleUITests.swift in Sources */, 803 | ); 804 | runOnlyForDeploymentPostprocessing = 0; 805 | }; 806 | /* End PBXSourcesBuildPhase section */ 807 | 808 | /* Begin PBXTargetDependency section */ 809 | 3AD916CE68B7707309E49AF7 /* PBXTargetDependency */ = { 810 | isa = PBXTargetDependency; 811 | name = SwinjectReactorKitExample; 812 | target = F48B8F3141E527587D1556AC /* SwinjectReactorKitExample */; 813 | targetProxy = 3C6DD1448E1252CAA0508C0A /* PBXContainerItemProxy */; 814 | }; 815 | CF87BE6DF2B6CDEAEAB878C8 /* PBXTargetDependency */ = { 816 | isa = PBXTargetDependency; 817 | name = SwinjectReactorKitExample; 818 | target = F48B8F3141E527587D1556AC /* SwinjectReactorKitExample */; 819 | targetProxy = 53D4C9BF9DD7EEFCA9B40B6F /* PBXContainerItemProxy */; 820 | }; 821 | /* End PBXTargetDependency section */ 822 | 823 | /* Begin PBXVariantGroup section */ 824 | F4996BF24A8D5D3FBC4C5B20 /* LaunchScreen.storyboard */ = { 825 | isa = PBXVariantGroup; 826 | children = ( 827 | 9C4D9A81FBFBC1C2B8911240 /* Base */, 828 | ); 829 | name = LaunchScreen.storyboard; 830 | sourceTree = ""; 831 | }; 832 | /* End PBXVariantGroup section */ 833 | 834 | /* Begin XCBuildConfiguration section */ 835 | 3A16DD8B961C478B02B0111C /* Debug */ = { 836 | isa = XCBuildConfiguration; 837 | baseConfigurationReference = AA2F42EAC242725F76825AA8 /* Pods-SwinjectReactorKitExampleTests.debug.xcconfig */; 838 | buildSettings = { 839 | BUNDLE_LOADER = "$(TEST_HOST)"; 840 | CODE_SIGN_IDENTITY = "iPhone Developer"; 841 | INFOPLIST_FILE = SwinjectReactorKitExampleTests/Info.plist; 842 | LD_RUNPATH_SEARCH_PATHS = ( 843 | "$(inherited)", 844 | "@executable_path/Frameworks", 845 | "@loader_path/Frameworks", 846 | ); 847 | PRODUCT_BUNDLE_IDENTIFIER = com.havi.SwinjectReactorKitExampleTests; 848 | PRODUCT_NAME = SwinjectReactorKitExampleTests; 849 | SDKROOT = iphoneos; 850 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 851 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 852 | SWIFT_COMPILATION_MODE = singlefile; 853 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 854 | SWIFT_VERSION = 5.4; 855 | TARGETED_DEVICE_FAMILY = "1,2"; 856 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwinjectReactorKitExample.app/SwinjectReactorKitExample"; 857 | TEST_TARGET_NAME = SwinjectReactorKitExample; 858 | }; 859 | name = Debug; 860 | }; 861 | 3F67E00977E8CD0385E9301C /* Debug */ = { 862 | isa = XCBuildConfiguration; 863 | buildSettings = { 864 | ALWAYS_SEARCH_USER_PATHS = NO; 865 | CLANG_ANALYZER_NONNULL = YES; 866 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 867 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 868 | CLANG_CXX_LIBRARY = "libc++"; 869 | CLANG_ENABLE_MODULES = YES; 870 | CLANG_ENABLE_OBJC_ARC = YES; 871 | CLANG_ENABLE_OBJC_WEAK = YES; 872 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 873 | CLANG_WARN_BOOL_CONVERSION = YES; 874 | CLANG_WARN_COMMA = YES; 875 | CLANG_WARN_CONSTANT_CONVERSION = YES; 876 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 877 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 878 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 879 | CLANG_WARN_EMPTY_BODY = YES; 880 | CLANG_WARN_ENUM_CONVERSION = YES; 881 | CLANG_WARN_INFINITE_RECURSION = YES; 882 | CLANG_WARN_INT_CONVERSION = YES; 883 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 884 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 885 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 886 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 887 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 888 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 889 | CLANG_WARN_STRICT_PROTOTYPES = YES; 890 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 891 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 892 | CLANG_WARN_UNREACHABLE_CODE = YES; 893 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 894 | COPY_PHASE_STRIP = NO; 895 | DEBUG_INFORMATION_FORMAT = dwarf; 896 | ENABLE_STRICT_OBJC_MSGSEND = YES; 897 | ENABLE_TESTABILITY = YES; 898 | GCC_C_LANGUAGE_STANDARD = gnu11; 899 | GCC_DYNAMIC_NO_PIC = NO; 900 | GCC_NO_COMMON_BLOCKS = YES; 901 | GCC_OPTIMIZATION_LEVEL = 0; 902 | GCC_PREPROCESSOR_DEFINITIONS = ( 903 | "DEBUG=1", 904 | "$(inherited)", 905 | ); 906 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 907 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 908 | GCC_WARN_UNDECLARED_SELECTOR = YES; 909 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 910 | GCC_WARN_UNUSED_FUNCTION = YES; 911 | GCC_WARN_UNUSED_VARIABLE = YES; 912 | MTL_ENABLE_DEBUG_INFO = YES; 913 | ONLY_ACTIVE_ARCH = YES; 914 | PRODUCT_NAME = "$(TARGET_NAME)"; 915 | }; 916 | name = Debug; 917 | }; 918 | 5993609AC3E834FA91CF0323 /* Debug */ = { 919 | isa = XCBuildConfiguration; 920 | baseConfigurationReference = EAD0CD3BDD883CA0E03D2A5F /* Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests.debug.xcconfig */; 921 | buildSettings = { 922 | CODE_SIGN_IDENTITY = "iPhone Developer"; 923 | INFOPLIST_FILE = SwinjectReactorKitExampleTests/Info.plist; 924 | LD_RUNPATH_SEARCH_PATHS = ( 925 | "$(inherited)", 926 | "@executable_path/Frameworks", 927 | "@loader_path/Frameworks", 928 | ); 929 | PRODUCT_BUNDLE_IDENTIFIER = com.havi.SwinjectReactorKitExampleUITests; 930 | PRODUCT_NAME = SwinjectReactorKitExampleUITests; 931 | SDKROOT = iphoneos; 932 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 933 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 934 | SWIFT_COMPILATION_MODE = singlefile; 935 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 936 | SWIFT_VERSION = 5.4; 937 | TARGETED_DEVICE_FAMILY = "1,2"; 938 | TEST_TARGET_NAME = SwinjectReactorKitExample; 939 | }; 940 | name = Debug; 941 | }; 942 | 6EE6444480B1E4FDF93BCC57 /* Debug */ = { 943 | isa = XCBuildConfiguration; 944 | baseConfigurationReference = B640595E0A7EEF5DD6EEBA9B /* Pods-SwinjectReactorKitExample.debug.xcconfig */; 945 | buildSettings = { 946 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 947 | CODE_SIGN_IDENTITY = "iPhone Developer"; 948 | ENABLE_PREVIEWS = YES; 949 | INFOPLIST_FILE = SwinjectReactorKitExample/Supporting/Info.plist; 950 | IPHONEOS_DEPLOYMENT_TARGET = 14.5; 951 | LD_RUNPATH_SEARCH_PATHS = ( 952 | "$(inherited)", 953 | "@executable_path/Frameworks", 954 | ); 955 | PRODUCT_BUNDLE_IDENTIFIER = com.havi.SwinjectReactorKitExample; 956 | PRODUCT_NAME = SwinjectReactorKitExample; 957 | SDKROOT = iphoneos; 958 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 959 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 960 | SWIFT_COMPILATION_MODE = singlefile; 961 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 962 | SWIFT_VERSION = 5.4; 963 | TARGETED_DEVICE_FAMILY = 1; 964 | }; 965 | name = Debug; 966 | }; 967 | 78A18FC62AA6F2262DE588EC /* Release */ = { 968 | isa = XCBuildConfiguration; 969 | baseConfigurationReference = A023A1A6FC82E2CBD03CA064 /* Pods-SwinjectReactorKitExample-SwinjectReactorKitExampleUITests.release.xcconfig */; 970 | buildSettings = { 971 | CODE_SIGN_IDENTITY = "iPhone Developer"; 972 | INFOPLIST_FILE = SwinjectReactorKitExampleTests/Info.plist; 973 | LD_RUNPATH_SEARCH_PATHS = ( 974 | "$(inherited)", 975 | "@executable_path/Frameworks", 976 | "@loader_path/Frameworks", 977 | ); 978 | PRODUCT_BUNDLE_IDENTIFIER = com.havi.SwinjectReactorKitExampleUITests; 979 | PRODUCT_NAME = SwinjectReactorKitExampleUITests; 980 | SDKROOT = iphoneos; 981 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 982 | SWIFT_COMPILATION_MODE = wholemodule; 983 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 984 | SWIFT_VERSION = 5.4; 985 | TARGETED_DEVICE_FAMILY = "1,2"; 986 | TEST_TARGET_NAME = SwinjectReactorKitExample; 987 | }; 988 | name = Release; 989 | }; 990 | A4D3F1A9BBAD293DA32432D0 /* Release */ = { 991 | isa = XCBuildConfiguration; 992 | baseConfigurationReference = CFC49AE8A66037B2C95EC069 /* Pods-SwinjectReactorKitExampleTests.release.xcconfig */; 993 | buildSettings = { 994 | BUNDLE_LOADER = "$(TEST_HOST)"; 995 | CODE_SIGN_IDENTITY = "iPhone Developer"; 996 | INFOPLIST_FILE = SwinjectReactorKitExampleTests/Info.plist; 997 | LD_RUNPATH_SEARCH_PATHS = ( 998 | "$(inherited)", 999 | "@executable_path/Frameworks", 1000 | "@loader_path/Frameworks", 1001 | ); 1002 | PRODUCT_BUNDLE_IDENTIFIER = com.havi.SwinjectReactorKitExampleTests; 1003 | PRODUCT_NAME = SwinjectReactorKitExampleTests; 1004 | SDKROOT = iphoneos; 1005 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 1006 | SWIFT_COMPILATION_MODE = wholemodule; 1007 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 1008 | SWIFT_VERSION = 5.4; 1009 | TARGETED_DEVICE_FAMILY = "1,2"; 1010 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwinjectReactorKitExample.app/SwinjectReactorKitExample"; 1011 | TEST_TARGET_NAME = SwinjectReactorKitExample; 1012 | }; 1013 | name = Release; 1014 | }; 1015 | E66205A43E30F34EE99E8D6C /* Release */ = { 1016 | isa = XCBuildConfiguration; 1017 | buildSettings = { 1018 | ALWAYS_SEARCH_USER_PATHS = NO; 1019 | CLANG_ANALYZER_NONNULL = YES; 1020 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 1021 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 1022 | CLANG_CXX_LIBRARY = "libc++"; 1023 | CLANG_ENABLE_MODULES = YES; 1024 | CLANG_ENABLE_OBJC_ARC = YES; 1025 | CLANG_ENABLE_OBJC_WEAK = YES; 1026 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 1027 | CLANG_WARN_BOOL_CONVERSION = YES; 1028 | CLANG_WARN_COMMA = YES; 1029 | CLANG_WARN_CONSTANT_CONVERSION = YES; 1030 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 1031 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 1032 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 1033 | CLANG_WARN_EMPTY_BODY = YES; 1034 | CLANG_WARN_ENUM_CONVERSION = YES; 1035 | CLANG_WARN_INFINITE_RECURSION = YES; 1036 | CLANG_WARN_INT_CONVERSION = YES; 1037 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 1038 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 1039 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 1040 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 1041 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 1042 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 1043 | CLANG_WARN_STRICT_PROTOTYPES = YES; 1044 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 1045 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 1046 | CLANG_WARN_UNREACHABLE_CODE = YES; 1047 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 1048 | COPY_PHASE_STRIP = NO; 1049 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 1050 | ENABLE_NS_ASSERTIONS = NO; 1051 | ENABLE_STRICT_OBJC_MSGSEND = YES; 1052 | GCC_C_LANGUAGE_STANDARD = gnu11; 1053 | GCC_NO_COMMON_BLOCKS = YES; 1054 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 1055 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 1056 | GCC_WARN_UNDECLARED_SELECTOR = YES; 1057 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 1058 | GCC_WARN_UNUSED_FUNCTION = YES; 1059 | GCC_WARN_UNUSED_VARIABLE = YES; 1060 | MTL_ENABLE_DEBUG_INFO = NO; 1061 | PRODUCT_NAME = "$(TARGET_NAME)"; 1062 | VALIDATE_PRODUCT = YES; 1063 | }; 1064 | name = Release; 1065 | }; 1066 | FC8D2EDB0723629ECDF70F63 /* Release */ = { 1067 | isa = XCBuildConfiguration; 1068 | baseConfigurationReference = 5BAB44F911707258AC1AB522 /* Pods-SwinjectReactorKitExample.release.xcconfig */; 1069 | buildSettings = { 1070 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 1071 | CODE_SIGN_IDENTITY = "iPhone Developer"; 1072 | ENABLE_PREVIEWS = YES; 1073 | INFOPLIST_FILE = SwinjectReactorKitExample/Supporting/Info.plist; 1074 | IPHONEOS_DEPLOYMENT_TARGET = 14.5; 1075 | LD_RUNPATH_SEARCH_PATHS = ( 1076 | "$(inherited)", 1077 | "@executable_path/Frameworks", 1078 | ); 1079 | PRODUCT_BUNDLE_IDENTIFIER = com.havi.SwinjectReactorKitExample; 1080 | PRODUCT_NAME = SwinjectReactorKitExample; 1081 | SDKROOT = iphoneos; 1082 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 1083 | SWIFT_COMPILATION_MODE = wholemodule; 1084 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 1085 | SWIFT_VERSION = 5.4; 1086 | TARGETED_DEVICE_FAMILY = 1; 1087 | }; 1088 | name = Release; 1089 | }; 1090 | /* End XCBuildConfiguration section */ 1091 | 1092 | /* Begin XCConfigurationList section */ 1093 | 10D04FF028D4CE3A170429CA /* Build configuration list for PBXNativeTarget "SwinjectReactorKitExampleUITests" */ = { 1094 | isa = XCConfigurationList; 1095 | buildConfigurations = ( 1096 | 5993609AC3E834FA91CF0323 /* Debug */, 1097 | 78A18FC62AA6F2262DE588EC /* Release */, 1098 | ); 1099 | defaultConfigurationIsVisible = 0; 1100 | defaultConfigurationName = Release; 1101 | }; 1102 | 8D0A3F77323229E38026000F /* Build configuration list for PBXNativeTarget "SwinjectReactorKitExampleTests" */ = { 1103 | isa = XCConfigurationList; 1104 | buildConfigurations = ( 1105 | 3A16DD8B961C478B02B0111C /* Debug */, 1106 | A4D3F1A9BBAD293DA32432D0 /* Release */, 1107 | ); 1108 | defaultConfigurationIsVisible = 0; 1109 | defaultConfigurationName = Release; 1110 | }; 1111 | E60175D7B8BB9AB54CAD49F6 /* Build configuration list for PBXProject "SwinjectReactorKitExample" */ = { 1112 | isa = XCConfigurationList; 1113 | buildConfigurations = ( 1114 | 3F67E00977E8CD0385E9301C /* Debug */, 1115 | E66205A43E30F34EE99E8D6C /* Release */, 1116 | ); 1117 | defaultConfigurationIsVisible = 0; 1118 | defaultConfigurationName = Release; 1119 | }; 1120 | FC104E555942D7946BDCB21E /* Build configuration list for PBXNativeTarget "SwinjectReactorKitExample" */ = { 1121 | isa = XCConfigurationList; 1122 | buildConfigurations = ( 1123 | 6EE6444480B1E4FDF93BCC57 /* Debug */, 1124 | FC8D2EDB0723629ECDF70F63 /* Release */, 1125 | ); 1126 | defaultConfigurationIsVisible = 0; 1127 | defaultConfigurationName = Release; 1128 | }; 1129 | /* End XCConfigurationList section */ 1130 | }; 1131 | rootObject = 12F2DC6F253DB0D10222AAA4 /* Project object */; 1132 | } 1133 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample.xcodeproj/xcshareddata/xcschemes/SwinjectReactorKitExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 34 | 40 | 41 | 42 | 44 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 81 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample.xcodeproj/xcshareddata/xcschemes/SwinjectReactorKitExampleTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 54 | 55 | 61 | 62 | 63 | 64 | 70 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample.xcodeproj/xcshareddata/xcschemes/SwinjectReactorKitExampleUITests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 54 | 55 | 61 | 62 | 63 | 64 | 70 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample.xcodeproj/xcuserdata/hansangjin.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Rx (Playground) 1.xcscheme 8 | 9 | isShown 10 | 11 | orderHint 12 | 5 13 | 14 | Rx (Playground) 2.xcscheme 15 | 16 | isShown 17 | 18 | orderHint 19 | 6 20 | 21 | Rx (Playground).xcscheme 22 | 23 | isShown 24 | 25 | orderHint 26 | 4 27 | 28 | Sample-iOS (Playground) 1.xcscheme 29 | 30 | isShown 31 | 32 | orderHint 33 | 2 34 | 35 | Sample-iOS (Playground) 2.xcscheme 36 | 37 | isShown 38 | 39 | orderHint 40 | 3 41 | 42 | Sample-iOS (Playground).xcscheme 43 | 44 | isShown 45 | 46 | orderHint 47 | 1 48 | 49 | SwinjectReactorKitExample.xcscheme_^#shared#^_ 50 | 51 | orderHint 52 | 22 53 | 54 | 55 | SuppressBuildableAutocreation 56 | 57 | 405C9D8D26579CFA00C33809 58 | 59 | primary 60 | 61 | 62 | 405C9DA326579CFB00C33809 63 | 64 | primary 65 | 66 | 67 | 405C9DAE26579CFB00C33809 68 | 69 | primary 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample.xcworkspace/.tuist-generated: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/havilog/SwinjectReactorKitExample/9e9bb5c82a7bfbc88d722717c0f61bd2cbec16dd/SwinjectReactorKitExample.xcworkspace/.tuist-generated -------------------------------------------------------------------------------- /SwinjectReactorKitExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample.xcworkspace/xcshareddata/xcschemes/SwinjectReactorKitExample-Project.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 44 | 50 | 51 | 52 | 53 | 54 | 59 | 60 | 62 | 68 | 69 | 70 | 72 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 109 | 111 | 117 | 118 | 119 | 120 | 122 | 123 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Resources/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Resources/Assets.xcassets/initial_empty_image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "empty.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Resources/Assets.xcassets/initial_empty_image.imageset/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/havilog/SwinjectReactorKitExample/9e9bb5c82a7bfbc88d722717c0f61bd2cbec16dd/SwinjectReactorKitExample/Resources/Assets.xcassets/initial_empty_image.imageset/empty.png -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Resources/Assets.xcassets/no_url_image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "empty2.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Resources/Assets.xcassets/no_url_image.imageset/empty2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/havilog/SwinjectReactorKitExample/9e9bb5c82a7bfbc88d722717c0f61bd2cbec16dd/SwinjectReactorKitExample/Resources/Assets.xcassets/no_url_image.imageset/empty2.png -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Resources/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 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Resources/indicator.json: -------------------------------------------------------------------------------- 1 | {"v":"4.8.0","meta":{"g":"LottieFiles AE 1.0.0","a":"","k":"","d":"","tc":""},"fr":24,"ip":0,"op":48,"w":500,"h":500,"nm":"circlesSynth","ddd":0,"assets":[{"id":"image_0","w":66,"h":66,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAABCCAYAAADjVADoAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAEH0lEQVR4nO2czXXiShCFb7W0BAFr4FgTwSOD4UUwTASjieARAs4AZ4AzgAzIYCADcbDXAsFu1Kq3cGMLLECApAbhb2XJTZ/iUtW/1U3IAdvzbGkYLWZuEZHNgH2g+ALMEyJyQyEmr6XSJA8bKauKm77fAdBhoA3g4YKqlgDGBAwNKYdurbZIxcAdUhXC9jw7MM0umB0AlTTrjjACUf+lXB6nWWkqQtTX6xaFYQ/AjzTqS8iMgN7csgZpVHaRELbnVaVh9Bn4lYYxZzIFUfdSDzlbiPpy2SWiHrILgdMgejKDoHduG3KyELbnVQPDGCDfMEjKjIXonNPTnCSEaguGuKwXyBwCfp/adiQWQokwxrWEwjGInl7K5W7S4iJJoabvOxSGf3ArIgAA839N3x8kLX7UI5Qn/LnIKI0Q8Dy3LOdYuYMeEQmHm4WBX03fd46V2+sRqneY4MobxsQQ/XtorLHXI1QXWQwRAIB5aHtedd+/Y4WoL5ddXOc44RIq6seN5VNoqJBwcUs9xAkQ8HNuWcPd9588QhpGHwUVAQAYGMSFyJYQ9fW6pXkClQeVQIhPA60tIdRUuvgQdXe94l0I2/NsFK+B3EflrxBO9MW7EIFpJh6XFwEi2vq+H6Hxtrx2Tzw0Vqv25kEA7wuthe0p9kGRH3/jER09puhFrbADUEJEX9wZD/X1ugUAQvUWxZlTnIqUbQAQ0jBamk3RiiB68whmvmshNtuPgohsrZbo5zsAiCMbsndDosXbomN7nv0lBIDANG2Br9AA8BYarm4jroGv0ADARIsvIQC8lkoTASCTVJxbQ4A5l2StK2YKvI0sXc2G6MYFABEKcd8eoSJCqOySpWZz9CHEGPjoPsfaDNHMZmNYAAABn7bA7oTR5g8BAIaUdylE1AEEAKiUvNHeTxSTZdQBPkaWRH0t5miCgK287q20gIbvu7iThVxTym9ureZunrc3gYFe3gbpgIDnqAjq3TYN358A+Ccvo3Sw6w1A3DR8Z3O0cDA/7ooAxAjxUi6PQfSUi1H5MzPDMLZTiF2PMIOgB2CWpUVaIHL2Ze/HCuHWagsWolgbw8yPZ+VZvpZKEwJ+Z2JU/oxeKpXeoQIHl+rmljUoQHsxNaV0jhVKdEyh6fuDG822m5pStpOc6kl8XuMGxUgsAnDCcv7cspxbaTMIeD5FBPWZ02isVm0wD3GtOVfMj8caxjjOOuV3pQfcZiByzj32eNG5z6bvdxgYQLd3MD+aYdi/5Lj0xSeBbc+rBkJ01RwlV0EIeDak7MXNHc6oKx1sz6v+FcJRGa1Zrmks1YH5VATYkMltAY3Vqk3MTgo3BUQZZXljQGbXJmyor9ctSNkWRC2VpvQ9wcemAFwwTyDEOO2bAeLIXIh9qCsW7M0zEy3yujQjjv8Bn39zEX49t44AAAAASUVORK5CYII=","e":1},{"id":"image_1","w":66,"h":66,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAABCCAYAAADjVADoAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAELUlEQVR4nO2cS3LiSBCG/yyJnQ32GhPWnGDoiDYRvWr6BMOcoNUnGI6Ab4BvgG8AN2BHBHYEcAMI7DWP9s4SOQsVbgECJPQoEP5WliiX0z+Z9cwqQgIYnYlhZ7QiMxeJyWCCsaP4FOA+MQ0XEP3X0kU/CRsprooLz/MKFqgwoQzgNkRVMwBtYjS1jN0cfrmeRmPhKpEKYXQmhpXRq2A2AeSirNtFC6D6y91lO8pKIxEi330rEi1qAP6Joj6fjIhRG5eyjSgqCyWE0Ztc2e9anQk/ozDmIAgDMFXDesjBQuSfZlUC1RBfCASD6EHXrNqhbUhgIYze5MqytAaSDQO/jJhF5ZCeJpAQsi1oIlwvEDvE+BW07fAthBShjWMJhX0QPbx8vaz6LS78FCp05ybRoodTEQEAmP8rdOcNv8X3eoT0hF4ooxRCjMdxKWvuK7fTI1zhcLIw4WehOzf3ldvqEbJ36OPIG0b/0I9dY42tHiG7yJSIAADcNHqTq22fegqRf5pVcZzjhDDk5JfryUZoyJAY4pR6iAAQ4d/x12xz/f2GR9jvWh0pFQEAmNHwCpEVIfLdt6LSCVQy5CxLbAy0VoSQU+kzgKrrXvEhhNGZGEhfA7mN3LslTPeLDyGsjO57XJ4GCLTy//4JDWd57Zy4vXn6XV4+CEAutKa4p9gGub58xyMWqKgyRiVyhR2AFML94sy4zXffigAgZG+RojlFQMguA4CwM1pRsSlKEUyORzDzWQux3H4UxGQotUQ93wFA7NmQPRt8Ld6mHaMzMT6FAGDpuiGAz9AAnNAYqjbiGPgMDQDMNP0UAsBr6aIvAMSSinNqCIATSdY6WggDwBlZDhWbohZ2OguxgDhvj5ARIWR2yUyxNQoRbeBP99lWZodilhvDAgCIsbEFdia0lj8IANAy9lkK4XYAAQAyJa+19TfSycztAK6RJdVVWKMKYqzkdX8IIRuNkQqjVKDZds39vLoJzFj5MK0Q43H47Xq48m690M3zvA/G34lZpQDdsv9aF2Jz9smU8s1gvl8XAfAQ4uXusg2ih0RsSp6Rri88OwXP9Qhds2pIZcNJ5rbsfU8hhl+up8wiZRvDfH9QnuVr6aJPjF+x2JQ8rZe7XG1XgZ1LdeNStnHy7QVhoOu2ub+YDwrdeeMks+0IA12zy35O9fg+r3FyYgQQAQiwnD8uZc1TaTOI8RhEBOCAM11OAhY3cbQ5V3y/r2H04qBTfkd6wG0EkHnoscdQ5z4Lz/MKMxpQ7h18r+uLepjj0qFPAjveIapwEjgTFYQYj5pt17zmDoHrisAeAI4g75YwZUZrnMlpM2I0oxJgSSy3Bdw8/S4TsxnBTQFuWnHeGBDbtQlL8t23IsguC6aiTFP67sOqgbMDxX1AtKO+GcD7TyrC6EwMS9eN5TMzTZO6NMOL/wFOX4B0B002hAAAAABJRU5ErkJggg==","e":1},{"id":"image_2","w":66,"h":66,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAABCCAYAAADjVADoAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAEK0lEQVR4nO2cTW7iSBTHf68C2SbLdIgUR+ogzY4bDHOCYU7Q9AkG34CcoMgNyA3IDbhBk1UkaClECtEsybLTtN8sMDQQQwwYG0x+G/xRKh5/Xn246j0LMXBi7x1DtgBaAHUEceaVVegDLUG7QKvn5ltx2CibqvjUfi+BVwIpIpyvXJHwgkdT0EaWbKPrXvQjNHPiayLkxN47B2QrarSMchRl3WOUWwO1J/eyGWW1kQiRs+2CIlWEv6OoLxTKo6DVnpuvR1HdWkI49uH4lZ81RL5EYcxKKHcGKut6yMpCfLKdihiqG2sCSyIq11kOqqv2IUsLMfSCQT3WZhCWYXMprTLSLCWE3xc01hoFYkBUvy7bd4QWImfbBTXS3Jam8B6ict1zP1fCljdhCuVsu6wi33ZFBAAV/ffUtuthy7/rETnbLqjIt7WsShLVm2c3X36v2EKPGDeHXUbkS862y+8Wm3fDHx1a294xhsUofy2aa8z1CH+ITIUIAJ6h4diH43n3A4X4ZDuVrZwnrINy9MqgPu/2m6bh2IfjVzPo7tIIsRQq/zy7nxuzl994xCs/a6kVAQCtBTWRKSFytl1I9AEqDoTzVwZvJlpTQihSjc2gJDFUZr1iLMSJvXdS10HOQzn6waA8eWksxAHZ0PPyNCAw9XvHQqjRcuzWJIlwfmY7xdGpAX+hNdUjRTAev/983yO8UkK2JIwUR0dm9sJeIZznbLsAYPzRIjXPFMvi+U5ghjtQ+4ugQ4/AP9hXRtuPBtRJ0pCkUeFPALNoQ3afCLV4m3aGu/UfkCHjGAUnaUO2ASPQTdqIbeCjaQCK9j+EAHpuvmX8mKW9xwCxBGttLcodgPGj1/aZLnx4BPi/3/TcfAvhJWlrksJA0/8EvOHJPjLaGDYAgr7ZAtsLlNvRoQHIkt1LISYdwAB03Yv+pDp7gfAy6QBm4qCWjEUJ4elUXPdYiCf3sonymIxV8ePxqzp5PvWsIejUzdSievOf+0d38tKUED03Xx9NOdPMrDdAwGO4mdkcTR3K1aw3QIAQT+5lU1SuYzEqbpTHQzKBg0LgekSWg2oaO04D5XnR+4FCdN2LvqDp2hhWrlaKs+y5+Zaoft2IUXGjevPsXlYXFVm4VNdz8/Wd7y+Uu8MQ0UCh0hRObbu+k9F2yt0hmWKYrJ7Q+Ro7J8YSIsASy/nPbr68M32G6s0yIsAKOV1ntlP0DI2tjblSrt7rGINYKctvKxPclEcD5VXTHtfK+zy130sYrSfuHcrVIZnaOunSa2cC+95RwVCJXRDVG49f1aBnh2WJLDfcsQ/HPxiUBSobDU4TXvC0EZUAv6vdAGe2UxwGc675poBJlNtNvjFgY69NGJGz7YKHFAUtCOKMYpYWMlwT6QItA82o3wwQxMaFmMeJvXcyZJzRuaL9uF6aEcT/7qKCgsHmSLUAAAAASUVORK5CYII=","e":1},{"id":"image_3","w":66,"h":66,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAABCCAYAAADjVADoAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAELklEQVR4nO2cTW7iWBDH//Wws02WdNNSHKmDNDtu0PQJJnOCdm/TaY2P4NzAUaOs4QbkBtygYYVERoqRmmiWZNmJcc3CNgPEgI0/Htj5bYLN01PlT73vqkfIgaox1ISjNgBuAKwRSFtXlglTMPpEbGOG/uS23s/DRsqq4vdX/1wA7gVATQCnCap6AqFH4K5aUbu2dTZNycQlUhWiagy1iqMaDNYBHKdZ9xzCnWBYv1rnvXSrTYHa5ajBFTLB+DON+iIyJmJz8qPeTqOyREJoxsPJs/NiAfQlDWN2ZCAAI6mH7CzEu2/3BhFMZNUEYkKgG1WpmLv2IbGF0IyHk+eZ0865GURlTC5f7DLSxBKidjlqsKAuko0CmUPEX+P2HZGF8EXoYU+awjYIdDNpfTSilhdRCtW+j3QW9BMHIgIAMPjv91ejdtTyWz3C94SfiaySCnceW3V9W6mNHrHQHA4Y+lL7PtK3llr3hTdHcPrY844xKgL4vGmusdYjnmdOGwURAQBcoKsZDyfrvg8V4t23e2NP5wlJOPZ/3FBeNQ2/Sdg4oBEiHvTXY+tjd/XtK4/w1g5FFQEA2AprIktC1C5HDckLqDw4fXacVxOtJSG4QmZu5sjFWPWKuRBVY6gVsINcx/HvF0dffDEXouKokeflRYAIS//vXAh/e61MnH64um8GDwIINlqLPFKE4y78+L5HuBeSbJEMNYNPYvVFyTj1pgyAqBpDDQVaU8TFJc8JhHcCVV6I2PMI7xiuvATHjwJgTaYhsmHgEwCITQeyZSLS5m3RqRpD7U0IAIqjaIIBTbYh+4AgwJZtxD7w1jQAsMvTNyEATG7rfcGETEJxDg0BRi7BWnvMAAAEEduSDZELeYOFwKzkHuG3COFHlzxJNkcaAuj5fwGQ91BGgoNhAQAEfnUEVgoId8FHAQBqRS2lEIsOIADAts6mi+qUhKdFB5jPLAXDkmOPLHgprnsuhN9pjGWYJANXmZmLz0trDSJe+rK4cOdf6w978c2SEH6Q5iBHi6Sw6g1AyDJcAEU/DL5e9QYgRIhfrfMegW5yMSl/xkeKEjoohO5HqErFRAE7TgHo66L3Q4WwrbMpuVy0g+HrneIsJ7f1PhF/zcSk3OHOY+vc3FRi41bd5Ee9XYD+YnCkbI8GipSm4EW5H2S03eBIUZpRsnoi52scoBiRRQBibOc/tur64fQZ3IkjArBDTteHq/umC3SxvzFX19s6xjB2yvLb0wS3sQD0XdMeE+V9etF43IZ877g+UhQrSbp04kxgP5rfgLdGyVkQ7rjKzAxbO8QltdxwzXg4+f3i6H5Ea5bBaU8Ad9MSICCT2wK8DpX1FG4K+B/CXZY3BmR2bUJA7XLUcImaRNwgkBbELG1hAIINRl8AvbRvBggjcyHWUTWGmuIoWvDMLk/zujQjjP8AhJ9y8IRgflgAAAAASUVORK5CYII=","e":1},{"id":"image_4","w":66,"h":66,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAABCCAYAAADjVADoAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAETUlEQVR4nO2cMXbiSBCG/yrheZOZG5hsU91g2GATxrzVnmA1FxijwMybDEe8gaDBJ4AbyA8/b7AJNxicbgQ3wOkgdW+AwIAFCCHUIPwFGKR+TfG7qlrqrhYhBeqWKLAPE4pNJhSUQmFtY4WxIgyIaAjfH1SfnEEaNtKhOv5RFhaDLaVQBHAVuyPCCyT6YHIvDN91XGecmJFLX5MgdUsUDI8rINhQuEyy7zkKD0Sydfvo9JPsNhEhGiVhgrgGwp9J9BeREYhq1d7XThKd7SWEsETe87mlFP5Owpg4EPAMyMq+HhJbiObn+4piVTtYCOxO+yIna3FzyM5CCEvkJxPupBwGURlBSivOSLOTEI2SMMHsYp9RIA2IvuyaOyIL0SgJEwb3jygUttGuPt5UojbmKI0a5XsbzD9PSAQAuGmW252ojbd6RBAOP/cySSNE6N72buxt7YxNJ+fhAHxMyC4dmH/8Vhr9+98/GxPoWo8QlshPPB7g2BNjRAjy903XGmtzxGTCHWREBABQxK6wRH7d+VAhmp/vK0d6nRAfhcvgnxvKm9AQlshPfB6e2AgRGUXyr289x109/sYjPJ9bWRUBAEhxKyxEloRolISp8wYqJa5+efzmQmvZI4hraVmjEyJUVr1iLkTdEoXMJch1KFx6E8NePDQXwghxlyyjSC393tfQINhpG6OZq+a1KM4+MDCdaM3ySLEWYnv2lqcvbGkzRiPBDDuAQIjFA2fGVaMkTADguiUKyNA9xa4QGUUAYPZharZFL6ymHgHFZy3EbPmRmTasQ54HnwCANy7InhGRJm+zTt0ShXchAOQ8FBh4Dw1gGhpD3UYcA++hAUBJjN+FAFB9cgYMhYOU4pwarAipFGsdK9NCE4CJaKjZFq0oNR0sGL5/1h4xiwiuPjkDEF50G6QLhuxP/wKARF+jLVqZLQxPhWB6swR2Fig8zN4yAFwY/nkKseAADACO64wX1TkLCC+LDjC/siSSLT0W6YGApbruuRBB0hjpMEoHniFri59XFoFp6WRWIUL3u+sMF48tCVHtfe3MLjmzzKo3AKG34TLTi8EKuFv1BiBEiCBXtFOwSQejD7nwQSF0PuIiJ2vIYOIkSHtd9X6oEI7rjCFlphaGFXAXq85yejNGXw5iVcoQofvt8aa2qc3Gqbqg1P+k8wUBzzlj+wAQaZtCs9zunGK1HQHPuZwsRtnVE3m/xqmJsYsIwA7T+be9G/tUcgYRuruIAMTY09W8FkVF7B5rzZUC7rYlxjBi7fI70g1uI4K042573Gvf54+ysAjc0e0dCrj7kJOtfbZL770TWFgi/8vjChEqaQtChK5nyFrYvcPOfSVgD4BgV/DEsIOK1sMVpxFeCHCTEuC12wPQvBZFENt7PylgEYWHQz4x4GCPTZjRKAmTyCiClRmUKX2KYNSzUhgqwoAh+0k/GWDNd+qhbolCznstUlES47QemhHG/8y3hLZbBuCQAAAAAElFTkSuQmCC","e":1}],"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"Layer 5","refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[379.615,249.999,0],"to":[0,11.667,0],"ti":[43.202,-11.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[379.615,319.999,0],"to":[-43.202,11.667,0],"ti":[43.202,11.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[120.4,319.999,0],"to":[-43.202,-11.667,0],"ti":[0,11.667,0]},{"t":36,"s":[120.4,250,0]}],"ix":2},"a":{"a":0,"k":[32.654,32.654,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":48,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":2,"nm":"Layer 4","refId":"image_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[314.807,249.999,0],"to":[0,11.667,0],"ti":[21.601,-11.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[314.807,320,0],"to":[-21.601,11.667,0],"ti":[21.601,11.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[185.2,320,0],"to":[-21.601,-11.667,0],"ti":[0,11.667,0]},{"t":47,"s":[185.2,250,0]}],"ix":2},"a":{"a":0,"k":[32.654,32.654,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":48,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":2,"nm":"Layer 3","refId":"image_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,249.999,0],"ix":2},"a":{"a":0,"k":[32.654,32.654,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,2.918]},"t":0,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":20,"s":[120,120,100]},{"t":48,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":0,"op":48,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":2,"nm":"Layer 2","refId":"image_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[185.193,249.999,0],"to":[0,-11.667,0],"ti":[-21.601,11.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[185.193,180,0],"to":[21.601,-11.667,0],"ti":[-21.601,-11.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[314.8,180,0],"to":[21.601,11.667,0],"ti":[0,-11.667,0]},{"t":47,"s":[314.8,250,0]}],"ix":2},"a":{"a":0,"k":[32.654,32.654,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":48,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":2,"nm":"Layer 1","refId":"image_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[120.386,249.999,0],"to":[0,0,0],"ti":[-43.202,11.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[120.386,179.999,0],"to":[43.202,-11.667,0],"ti":[-43.202,-11.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":20,"s":[379.6,179.999,0],"to":[43.202,11.667,0],"ti":[0,-11.667,0]},{"t":36,"s":[379.6,250,0]}],"ix":2},"a":{"a":0,"k":[32.653,32.654,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":48,"st":0,"bm":0}],"markers":[]} -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Resources/progress_bar.json: -------------------------------------------------------------------------------- 1 | {"v":"4.6.0","fr":29.9700012207031,"ip":0,"op":61.0000024845809,"w":400,"h":400,"nm":"Comp 1","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.372,"y":0.995},"o":{"x":0.333,"y":0},"n":"0p372_0p995_0p333_0","t":-1,"s":[-63.707,132,0],"e":[508.793,132,0],"to":[95.4166641235352,0,0],"ti":[-95.4166641235352,0,0]},{"t":65.0000026475043}]},"a":{"a":0,"k":[200,200,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"w":400,"h":400,"ip":-1.00000004073083,"op":899.000036617021,"st":-1.00000004073083,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.663,"y":0.994},"o":{"x":0.333,"y":0},"n":"0p663_0p994_0p333_0","t":47,"s":[-120.707,132,0],"e":[480.293,132,0],"to":[100.166664123535,0,0],"ti":[-100.166664123535,0,0]},{"t":120.0000048877}]},"a":{"a":0,"k":[200,200,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"w":400,"h":400,"ip":47.0000019143492,"op":947.000038572101,"st":47.0000019143492,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"Master","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[198,192,0]},"a":{"a":0,"k":[146.5,5.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-2.858,0],[0,0],[0,-2.858],[2.859,0],[0,0],[0,2.858]],"o":[[0,0],[2.859,0],[0,2.858],[0,0],[-2.858,0],[0,-2.858]],"v":[[-140.825,-5.175],[140.825,-5.175],[146,0.001],[140.825,5.175],[-140.825,5.175],[-146,0.001]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.847,0.847,0.847,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[146.25,5.425],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":900.000036657751,"st":0,"bm":0,"sr":1}]},{"id":"comp_1","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 5/progressbar-final Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[296,260,0]},"a":{"a":0,"k":[76.5,5.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-2.858,0],[0,0],[0,-2.859],[2.859,0],[0,0],[0,2.857]],"o":[[0,0],[2.859,0],[0,2.857],[0,0],[-2.858,0],[0,-2.859]],"v":[[-70.825,-5.175],[70.825,-5.175],[76,0],[70.825,5.175],[-70.825,5.175],[-76,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0,0.455,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[76.25,5.425],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":900.000036657751,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"Layer 4/progressbar-final Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[86,260,0]},"a":{"a":0,"k":[22.5,5.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-2.858,0],[0,0],[0,-2.859],[2.858,0],[0,0],[0,2.857]],"o":[[0,0],[2.858,0],[0,2.857],[0,0],[-2.858,0],[0,-2.859]],"v":[[-16.825,-5.175],[16.825,-5.175],[22,0],[16.825,5.175],[-16.825,5.175],[-22,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0,0.455,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[22.25,5.425],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":900.000036657751,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"Layer 3/progressbar-final Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[164,260,0]},"a":{"a":0,"k":[40,5.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-2.858,0],[0,0],[0,-2.859],[2.858,0],[0,0],[0,2.857]],"o":[[0,0],[2.858,0],[0,2.857],[0,0],[-2.858,0],[0,-2.859]],"v":[[-34.325,-5.175],[34.325,-5.175],[39.5,0],[34.325,5.175],[-34.325,5.175],[-39.5,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0,0.455,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[39.75,5.425],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":900.000036657751,"st":0,"bm":0,"sr":1}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_0","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[202.032,208.014,0]},"a":{"a":0,"k":[200,200,0]},"s":{"a":0,"k":[99.979,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[4.821,0],[0,0],[0,-4.821],[-4.821,0],[0,0],[0,2.771]],"o":[[0,0],[-4.821,0],[0,4.821],[0,0],[4.821,0],[0,-2.417]],"v":[[337.122,186.522],[59.625,186.49],[52.02,192.229],[59.708,197.449],[337.205,197.481],[343.914,191.917]],"c":true}},"o":{"a":0,"k":100},"x":{"a":0,"k":0},"nm":"Mask 2"}],"w":400,"h":400,"ip":0,"op":900.000036657751,"st":0,"bm":0,"sr":1}]} 2 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/Application/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/05/21. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | func application( 13 | _ application: UIApplication, 14 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 15 | ) -> Bool { 16 | return true 17 | } 18 | 19 | // MARK: UISceneSession Lifecycle 20 | 21 | func application( 22 | _ application: UIApplication, 23 | configurationForConnecting connectingSceneSession: UISceneSession, 24 | options: UIScene.ConnectionOptions 25 | ) -> UISceneConfiguration { 26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/Application/DI/DIContainer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DIContainer.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/05/24. 6 | // 7 | 8 | import Foundation 9 | import Swinject 10 | import SwinjectSafeAuto 11 | // import PureSwinject 12 | import Moya 13 | 14 | final class DIContainer { 15 | 16 | // MARK: Singleton 17 | 18 | static let shared: DIContainer = .init() 19 | private init() { 20 | // configureContainerSwinjectSafeAuto() 21 | configureContainer() 22 | print(#file.split(separator: "/").last!, #function) 23 | } 24 | 25 | private let container: Container = .init() 26 | 27 | private func configureContainer() { 28 | container.register(Bool.self, name: "isStub") { resolver in 29 | false 30 | } 31 | 32 | container.register(NetworkRepositoryType.self) { resolver in 33 | NetworkRepository() 34 | } 35 | 36 | container.register(URLSessionType.self) { resolver in 37 | URLSession.init(configuration: .default) 38 | } 39 | 40 | container.register(ImageServiceType.self) { resolver in 41 | ImageService.init() 42 | } 43 | 44 | container.register(SearchServiceType.self) { resolver in 45 | SearchService.init() 46 | } 47 | } 48 | 49 | private func configureContainerSwinjectSafeAuto() { 50 | // TODO: 에러 잡기 51 | // container.autoregister(MoyaProvider.self, initializer: MoyaProvider.init) 52 | // container.autoregister(URLSessionType.self, initializer: URLSession.init) 53 | // container.autoregister(ImageServiceType.self, initializer: ImageService.init) 54 | // container.autoregister(SearchServiceType.self, initializer: SearchService.init) 55 | // try! container.verify() 56 | } 57 | 58 | private func configureContainerPureSwinject() { 59 | } 60 | 61 | func getContainter() -> Container { 62 | return self.container 63 | } 64 | 65 | func resolve(name: String? = nil) -> T { 66 | guard let dependency = container.resolve(T.self, name: name) else { 67 | fatalError("\(T.self) Error") 68 | } 69 | 70 | print(T.self, "resolved") 71 | 72 | return dependency 73 | } 74 | } 75 | 76 | @propertyWrapper 77 | final class Dependency { 78 | let wrappedValue: T 79 | 80 | init() { 81 | // 앱 실행 시 isStub는 false, Test에서 true로 다시 register 82 | let isStub: Bool = DIContainer.shared.resolve(name: "isStub") 83 | self.wrappedValue = DIContainer.shared.resolve(name: isStub ? "stub" : nil) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/Application/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/05/21. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | var window: UIWindow? 12 | 13 | func scene( 14 | _ scene: UIScene, 15 | willConnectTo session: UISceneSession, 16 | options connectionOptions: UIScene.ConnectionOptions 17 | ) { 18 | guard let scene = (scene as? UIWindowScene) else { return } 19 | 20 | let window = UIWindow(windowScene: scene) 21 | 22 | let searchReactor: SearchReactor = .init() 23 | 24 | let vc = SearchViewController(reactor: searchReactor) 25 | 26 | window.rootViewController = vc 27 | window.makeKeyAndVisible() 28 | 29 | self.window = window 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/BusinessLayer/Service/ImageService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageService.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/06/14. 6 | // 7 | 8 | import Foundation 9 | 10 | import Moya 11 | import RxSwift 12 | 13 | // MARK: URLSession Mock 14 | 15 | protocol URLSessionType { 16 | func dataTask( 17 | with request: URLRequest, 18 | completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void 19 | ) -> URLSessionDataTask 20 | } 21 | 22 | extension URLSession: URLSessionType {} 23 | 24 | // MARK: ImageService 25 | 26 | protocol ImageServiceType { 27 | func fetchImage(with url: URL?) -> Single 28 | } 29 | 30 | final class ImageService: ImageServiceType { 31 | 32 | @Dependency private var urlSession: URLSessionType 33 | private var task: URLSessionTask? 34 | 35 | func fetchData(url: URL, completion: @escaping (Result) -> Void) { 36 | let request = URLRequest(url: url) 37 | 38 | // before task 39 | self.task?.cancel() 40 | 41 | // current task 42 | let task = self.urlSession.dataTask(with: request) { data, response, error in 43 | guard error == nil else { 44 | print("ImageDownloadError.networkError", error!.localizedDescription) 45 | completion(.failure(ImageDownloadError.networkError)) 46 | return 47 | } 48 | 49 | guard let response = response as? HTTPURLResponse else { 50 | print("ImageDownloadError.responseError") 51 | completion(.failure(ImageDownloadError.responseError)) 52 | return 53 | } 54 | 55 | guard 200..<300 ~= response.statusCode else { 56 | print("ImageDownloadError.statusError") 57 | completion(.failure(ImageDownloadError.statusError)) 58 | return 59 | } 60 | 61 | guard data != nil else { 62 | print("ImageDownloadError.dataError") 63 | completion(.failure(ImageDownloadError.dataError)) 64 | return 65 | } 66 | 67 | print("data received") 68 | completion(.success(data!)) 69 | 70 | CachStorage.shared.cachedImage.setObject(data! as NSData, forKey: url as NSURL) 71 | } 72 | 73 | task.resume() 74 | 75 | self.task = task 76 | } 77 | 78 | func fetchImage(with url: URL?) -> Single { 79 | return Single.create { [weak self] single in 80 | guard let self = self else { 81 | print("self error") 82 | single(.error(ImageDownloadError.selfError)) 83 | return Disposables.create() 84 | } 85 | 86 | guard let url = url else { 87 | print("url error") 88 | single(.error(ImageDownloadError.urlError)) 89 | return Disposables.create() 90 | } 91 | 92 | // cache에서 검사해서 있으면 리턴 93 | if let cachedImage = CachStorage.shared.cachedImage.object(forKey: url as NSURL) { 94 | print("cached Image returned") 95 | single(.success(cachedImage as Data)) 96 | return Disposables.create() 97 | } 98 | 99 | // cache가 없으면 Network통신 100 | self.fetchData(url: url) { result in 101 | switch result { 102 | case .success(let data): 103 | single(.success(data)) 104 | 105 | case .failure(let error): 106 | single(.error(error)) 107 | } 108 | } 109 | 110 | return Disposables.create { 111 | self.task?.cancel() 112 | } 113 | } 114 | } 115 | } 116 | 117 | enum ImageDownloadError: Error { 118 | case selfError 119 | case urlError 120 | case networkError 121 | case responseError 122 | case statusError 123 | case dataError 124 | } 125 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/BusinessLayer/Service/SearchService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PurchaseService.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/05/21. 6 | // 7 | 8 | import Foundation 9 | import RxSwift 10 | import Moya 11 | import Swinject 12 | 13 | struct SearchUserResult: Equatable { 14 | let nickname: String? 15 | let urlData: Data? 16 | let id: Int? 17 | } 18 | 19 | protocol SearchServiceType: AnyObject { 20 | func searchUser(id: String) -> Observable 21 | } 22 | 23 | final class SearchService: SearchServiceType { 24 | // swinject를 property wrapper로 감싸 dependency injection 25 | @Dependency var networkRepository: NetworkRepositoryType 26 | @Dependency var imageService: ImageServiceType 27 | 28 | func searchUser(id: String) -> Observable { 29 | return self.networkRepository.fetch(endpoint: .searchUser(query: id), for: User.self) 30 | .map { user -> (nickname: String?, url: URL?, id: Int?) in 31 | let item = user.items.first 32 | 33 | return ( 34 | nickname: item?.login, 35 | url: URL(string: item?.avatar_url ?? ""), 36 | id: item?.id 37 | ) 38 | } 39 | .asObservable() 40 | .flatMapLatest { [weak self] result -> Observable in 41 | guard let self = self else { return .empty() } 42 | 43 | return self.imageService.fetchImage(with: result.url) 44 | .asObservable() 45 | .catchError { error -> Observable in 46 | print("Error catched in searchService") 47 | return .just(nil) 48 | } 49 | .map { data -> SearchUserResult in 50 | return SearchUserResult(nickname: result.nickname, urlData: data, id: result.id) 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/DataLayer/Cache/CacheStorage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CacheStorage.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/06/14. 6 | // 7 | 8 | import Foundation 9 | 10 | final class CachStorage { 11 | static let shared = CachStorage() 12 | let cachedImage: NSCache 13 | 14 | private init() { 15 | cachedImage = .init() 16 | cachedImage.countLimit = 1000 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/DataLayer/Model/Joke.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Joke.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/06/15. 6 | // 7 | 8 | import Foundation 9 | 10 | struct JokeReponse: Decodable { 11 | let type: String 12 | let value: Joke 13 | } 14 | 15 | struct Joke: Decodable { 16 | let id: Int 17 | let joke: String 18 | let categories: [String] 19 | } 20 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/DataLayer/Model/User.swift: -------------------------------------------------------------------------------- 1 | // 2 | // User.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/06/11. 6 | // 7 | 8 | import Foundation 9 | 10 | struct User: Codable { 11 | let total_count: Int 12 | let incomplete_results: Bool 13 | let items: [Item] 14 | } 15 | 16 | extension User { 17 | struct Item: Codable { 18 | let login: String 19 | let id: Int 20 | let node_id: String 21 | let avatar_url: String 22 | let gravatar_id: String 23 | let url: String 24 | let html_url: String 25 | let followers_url: String 26 | let following_url: String 27 | let gists_url: String 28 | let starred_url: String 29 | let subscriptions_url: String 30 | let organizations_url: String 31 | let repos_url: String 32 | let events_url: String 33 | let received_events_url: String 34 | let type: String 35 | let site_admin: Bool 36 | let score: Int 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/DataLayer/Network/NetworkAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkAPI.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/06/11. 6 | // 7 | 8 | import Foundation 9 | import Moya 10 | 11 | enum NetworkAPI { 12 | case searchUser(query: String) 13 | } 14 | 15 | extension NetworkAPI { 16 | static var baseURLForTest: URL = URL(string: "https://avatars.githubusercontent.com/u/57659933?v=4")! 17 | 18 | static let sampleDataForTest: Data = Data( 19 | """ 20 | { 21 | "total_count": 1, 22 | "incomplete_results": false, 23 | "items": [ 24 | { 25 | "login": "hansangjin96", 26 | "id": 57659933, 27 | "node_id": "MDQ6VXNlcjU3NjU5OTMz", 28 | "avatar_url": "https://avatars.githubusercontent.com/u/57659933?v=4", 29 | "gravatar_id": "", 30 | "url": "https://api.github.com/users/hansangjin96", 31 | "html_url": "https://github.com/hansangjin96", 32 | "followers_url": "https://api.github.com/users/hansangjin96/followers", 33 | "following_url": "https://api.github.com/users/hansangjin96/following{/other_user}", 34 | "gists_url": "https://api.github.com/users/hansangjin96/gists{/gist_id}", 35 | "starred_url": "https://api.github.com/users/hansangjin96/starred{/owner}{/repo}", 36 | "subscriptions_url": "https://api.github.com/users/hansangjin96/subscriptions", 37 | "organizations_url": "https://api.github.com/users/hansangjin96/orgs", 38 | "repos_url": "https://api.github.com/users/hansangjin96/repos", 39 | "events_url": "https://api.github.com/users/hansangjin96/events{/privacy}", 40 | "received_events_url": "https://api.github.com/users/hansangjin96/received_events", 41 | "type": "User", 42 | "site_admin": false, 43 | "score": 1 44 | } 45 | ] 46 | } 47 | """.utf8 48 | ) 49 | } 50 | 51 | extension NetworkAPI: TargetType { 52 | var baseURL: URL { 53 | return URL(string: "https://api.github.com")! 54 | } 55 | 56 | var path: String { 57 | switch self { 58 | case .searchUser: 59 | return "search/users" 60 | } 61 | } 62 | 63 | var method: Moya.Method { 64 | return .get 65 | } 66 | 67 | var sampleData: Data { 68 | switch self { 69 | default: 70 | let user = User( 71 | total_count: 1, 72 | incomplete_results: false, 73 | items: [ 74 | User.Item( 75 | login: "hansangjin96", 76 | id: 57659933, 77 | node_id: "MDQ6VXNlcjU3NjU5OTMz", 78 | avatar_url: "https://avatars.githubusercontent.com/u/57659933?v=4", 79 | gravatar_id: "", 80 | url: "https://api.github.com/users/hansangjin96", 81 | html_url: "https://github.com/hansangjin96", 82 | followers_url: "https://api.github.com/users/hansangjin96/followers", 83 | following_url: "https://api.github.com/users/hansangjin96/following{/other_user}", 84 | gists_url: "https://api.github.com/users/hansangjin96/gists{/gist_id}", 85 | starred_url: "https://api.github.com/users/hansangjin96/starred{/owner}{/repo}", 86 | subscriptions_url: "https://api.github.com/users/hansangjin96/subscriptions", 87 | organizations_url: "https://api.github.com/users/hansangjin96/orgs", 88 | repos_url: "https://api.github.com/users/hansangjin96/repos", 89 | events_url: "https://api.github.com/users/hansangjin96/events{/privacy}", 90 | received_events_url: "https://api.github.com/users/hansangjin96/received_events", 91 | type: "User", 92 | site_admin: false, 93 | score: 1 94 | ) 95 | ] 96 | ) 97 | 98 | return try! JSONEncoder().encode(user) 99 | 100 | // if let data = try? JSONEncoder().encode(user) { 101 | // return data 102 | // } else { 103 | // return Data() 104 | // } 105 | } 106 | 107 | } 108 | 109 | var task: Task { 110 | switch self { 111 | case .searchUser(let query): 112 | return .requestParameters(parameters: ["q": query], encoding: URLEncoding.default) 113 | } 114 | } 115 | 116 | var headers: [String: String]? { 117 | return ["User-Agent": "request"] 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/DataLayer/Network/NetworkRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MoyaProvider.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/06/16. 6 | // 7 | 8 | import Foundation 9 | 10 | import RxSwift 11 | import Moya 12 | 13 | protocol NetworkRepositoryType { 14 | // Moya를 위한 protocol 15 | // associatedtype T: TargetType 16 | var provider: MoyaProvider { get } 17 | init( 18 | isStub: Bool, 19 | sampleStatusCode: Int, 20 | customEndpointClosure: ((NetworkAPI) -> Endpoint)? 21 | ) 22 | 23 | func fetch(endpoint: NetworkAPI, for type: Model.Type) -> Single 24 | } 25 | 26 | extension NetworkRepositoryType { 27 | static func consProvider( 28 | _ isStub: Bool = false, 29 | _ sampleStatusCode: Int = 200, 30 | _ customEndpointClosure: ((NetworkAPI) -> Endpoint)? = nil 31 | ) -> MoyaProvider { 32 | if isStub == false { 33 | return MoyaProvider() 34 | } else { 35 | // 테스트 시에 호출되는 stub 클로져 36 | let endPointClosure = { (target: NetworkAPI) -> Endpoint in 37 | let sampleResponseClosure: () -> EndpointSampleResponse = { 38 | EndpointSampleResponse.networkResponse(sampleStatusCode, target.sampleData) 39 | } 40 | 41 | return Endpoint( 42 | url: URL(target: target).absoluteString, 43 | sampleResponseClosure: sampleResponseClosure, 44 | method: target.method, 45 | task: target.task, 46 | httpHeaderFields: target.headers 47 | ) 48 | } 49 | return MoyaProvider( 50 | endpointClosure: customEndpointClosure ?? endPointClosure, 51 | stubClosure: MoyaProvider.immediatelyStub 52 | ) 53 | } 54 | } 55 | } 56 | 57 | final class NetworkRepository: NetworkRepositoryType { 58 | 59 | let provider: MoyaProvider 60 | 61 | init( 62 | isStub: Bool = false, 63 | sampleStatusCode: Int = 200, 64 | customEndpointClosure: ((NetworkAPI) -> Endpoint)? = nil 65 | ) { 66 | self.provider = Self.consProvider(isStub, sampleStatusCode, customEndpointClosure) 67 | } 68 | 69 | func fetch(endpoint: NetworkAPI, for type: Model.Type) -> Single { 70 | return provider.rx.request(endpoint) 71 | .filterSuccessfulStatusCodes() 72 | .map(Model.self) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/PresentationLayer/Search/SearchReactor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewReactor.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/05/24. 6 | // 7 | 8 | import RxSwift 9 | import ReactorKit 10 | 11 | final class SearchReactor: Reactor { 12 | 13 | // MARK: Events 14 | 15 | enum Action { 16 | case searchUser(id: String) 17 | } 18 | 19 | enum Mutation { 20 | case setSearchResult(SearchUserResult) 21 | } 22 | 23 | struct State { 24 | var searchResult: String = "before button pressed nickname" 25 | var searchAvartarImageData: Data? 26 | var searchIDResult: String = "before button pressed id" 27 | } 28 | 29 | // MARK: Properties 30 | 31 | @Dependency private var searchService: SearchServiceType 32 | 33 | let initialState: State 34 | let errorResult: PublishSubject = .init() 35 | 36 | // MARK: Initializers 37 | 38 | init() { 39 | initialState = State() 40 | } 41 | } 42 | 43 | // MARK: Mutation 44 | 45 | extension SearchReactor { 46 | func mutate(action: Action) -> Observable { 47 | switch action { 48 | case let .searchUser(id): 49 | return self.searchUser(with: id) 50 | } 51 | } 52 | } 53 | 54 | // MARK: Reduce 55 | 56 | extension SearchReactor { 57 | func reduce(state: State, mutation: Mutation) -> State { 58 | var newState = state 59 | switch mutation { 60 | case let .setSearchResult(result): 61 | newState.searchResult = result.nickname ?? "없음" 62 | newState.searchAvartarImageData = result.urlData 63 | newState.searchIDResult = String(result.id ?? 0) 64 | } 65 | return newState 66 | } 67 | } 68 | 69 | // MARK: Private Method 70 | 71 | private extension SearchReactor { 72 | func searchUser(with id: String) -> Observable { 73 | return searchService.searchUser(id: id) 74 | .catchError { [weak self] error in 75 | print("Error searchService catched!!!!!") 76 | self?.errorResult.onNext(error) 77 | return .empty() 78 | } 79 | .do(onNext: { print($0) }) 80 | .map { .setSearchResult($0) } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Sources/PresentationLayer/Search/SearchViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SwinjectReactorKitExample 4 | // 5 | // Created by 한상진 on 2021/05/21. 6 | // 7 | 8 | import Then 9 | import UIKit 10 | import Lottie 11 | import SnapKit 12 | import RxCocoa 13 | import ReactorKit 14 | 15 | final class SearchViewController: UIViewController { 16 | 17 | // MARK: Property 18 | 19 | var disposeBag: DisposeBag = .init() 20 | 21 | // MARK: UI Property 22 | 23 | private let searchIDTextField: UITextField = .init().then { 24 | $0.placeholder = "Git id 입력" 25 | } 26 | 27 | private let startButton: UIButton = .init(type: .system).then { 28 | $0.setTitle("startButton", for: UIControl.State()) 29 | } 30 | 31 | private let resultText: UILabel = .init() 32 | 33 | private let resultImageView: UIImageView = .init().then { 34 | $0.contentMode = .scaleAspectFit 35 | } 36 | 37 | private let indicator: AnimationView = .init(name: "progress_bar").then { 38 | $0.contentMode = .scaleAspectFit 39 | $0.isHidden = true 40 | } 41 | 42 | private let resultIDText: UILabel = .init() 43 | 44 | // MARK: Init 45 | 46 | init(reactor: SearchReactor) { 47 | super.init(nibName: nil, bundle: nil) 48 | self.reactor = reactor 49 | } 50 | 51 | required init?(coder: NSCoder) { 52 | fatalError("init(coder:) has not been implemented") 53 | } 54 | 55 | // MARK: Life Cycle 56 | 57 | override func viewDidLoad() { 58 | super.viewDidLoad() 59 | setUpUI() 60 | } 61 | 62 | override func viewWillAppear(_ animated: Bool) { 63 | super.viewWillAppear(animated) 64 | 65 | let temp = R.image.initial_empty_image() 66 | self.resultImageView.image = temp 67 | } 68 | } 69 | 70 | // MARK: UI 71 | 72 | extension SearchViewController { 73 | private func setUpUI() { 74 | view.backgroundColor = .systemGray6 75 | 76 | self.view.addSubview(self.indicator) 77 | self.indicator.snp.makeConstraints { 78 | $0.center.equalToSuperview() 79 | $0.size.equalTo(50) 80 | } 81 | 82 | self.view.addSubview(self.searchIDTextField) 83 | self.searchIDTextField.snp.makeConstraints { 84 | $0.top.equalToSuperview().offset(300) 85 | $0.width.equalTo(200) 86 | $0.centerX.equalToSuperview() 87 | } 88 | 89 | self.view.addSubview(self.startButton) 90 | self.startButton.snp.makeConstraints { 91 | $0.top.equalTo(self.searchIDTextField.snp.bottom).offset(20) 92 | $0.centerX.equalToSuperview() 93 | } 94 | 95 | self.view.addSubview(self.resultText) 96 | self.resultText.snp.makeConstraints { 97 | $0.top.equalTo(self.startButton.snp.bottom).offset(20) 98 | $0.centerX.equalToSuperview() 99 | } 100 | 101 | self.view.addSubview(self.resultImageView) 102 | self.resultImageView.snp.makeConstraints { 103 | $0.top.equalTo(self.resultText.snp.bottom).offset(20) 104 | $0.size.equalTo(200) 105 | $0.centerX.equalToSuperview() 106 | } 107 | 108 | self.view.addSubview(self.resultIDText) 109 | self.resultIDText.snp.makeConstraints { 110 | $0.top.equalTo(self.resultImageView.snp.bottom).offset(20) 111 | $0.centerX.equalToSuperview() 112 | } 113 | } 114 | } 115 | 116 | // MARK: Bind 117 | 118 | extension SearchViewController: View { 119 | func bind(reactor: SearchReactor) { 120 | bindAction(reactor: reactor) 121 | bindState(reactor: reactor) 122 | } 123 | 124 | private func bindAction(reactor: SearchReactor) { 125 | startButton.rx.tap 126 | .map { [weak self] in 127 | return Reactor.Action.searchUser(id: self?.searchIDTextField.text ?? "") 128 | } 129 | .do(onNext: { [weak self] _ in 130 | self?.indicator.isHidden = false 131 | self?.indicator.play() 132 | }) 133 | .bind(to: reactor.action) 134 | .disposed(by: disposeBag) 135 | } 136 | 137 | private func bindState(reactor: SearchReactor) { 138 | reactor.state 139 | .map(\.searchResult) 140 | .bind(to: resultText.rx.text) 141 | .disposed(by: disposeBag) 142 | 143 | reactor.state 144 | .map(\.searchAvartarImageData) 145 | .map { $0 == nil ? R.image.no_url_image() : UIImage(data: $0!) } 146 | .do(onNext: { [weak self] _ in 147 | self?.indicator.isHidden = true 148 | self?.indicator.stop() 149 | }) 150 | .bind(to: resultImageView.rx.image) 151 | .disposed(by: disposeBag) 152 | 153 | reactor.state 154 | .map(\.searchIDResult) 155 | .bind(to: resultIDText.rx.text) 156 | .disposed(by: disposeBag) 157 | 158 | reactor.errorResult 159 | .observeOn(MainScheduler.instance) 160 | .do(onNext: { [weak self] _ in 161 | self?.indicator.isHidden = true 162 | self?.indicator.stop() 163 | }) 164 | .subscribe(onNext: { 165 | print("error: ", $0) 166 | }) 167 | .disposed(by: disposeBag) 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /SwinjectReactorKitExample/Supporting/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | 37 | 38 | 39 | 40 | UIApplicationSupportsIndirectInputEvents 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIRequiredDeviceCapabilities 45 | 46 | armv7 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UISupportedInterfaceOrientations~ipad 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationPortraitUpsideDown 58 | UIInterfaceOrientationLandscapeLeft 59 | UIInterfaceOrientationLandscapeRight 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleTests/Mock/MockImageService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MockImageService.swift 3 | // SwinjectReactorKitExampleTests 4 | // 5 | // Created by 한상진 on 2021/06/16. 6 | // 7 | 8 | @testable import SwinjectReactorKitExample 9 | import Foundation 10 | import RxSwift 11 | 12 | final class MockImageService: ImageServiceType { 13 | 14 | private var makeRequestFail = false 15 | 16 | init(makeRequestFail: Bool = false) { 17 | self.makeRequestFail = makeRequestFail 18 | } 19 | 20 | func fetchImage(with url: URL?) -> Single { 21 | Single.create { [weak self] single in 22 | guard let self = self else { 23 | single(.error(ImageDownloadError.selfError)) 24 | return Disposables.create() 25 | } 26 | 27 | if self.makeRequestFail { 28 | single(.error(ImageDownloadError.dataError)) 29 | } else { 30 | single(.success(Data("test".utf8))) 31 | } 32 | 33 | return Disposables.create() 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleTests/Mock/MockNetworkRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MockNetworkRepository.swift 3 | // SwinjectReactorKitExampleTests 4 | // 5 | // Created by 한상진 on 2021/06/17. 6 | // 7 | 8 | import Foundation 9 | import Moya 10 | import RxSwift 11 | 12 | @testable import SwinjectReactorKitExample 13 | 14 | //class MockNetworkRepository: NetworkRepositoryType { 15 | // var provider: MoyaProvider 16 | // 17 | // required init(isStub: Bool, sampleStatusCode: Int, customEndpointClosure: ((NetworkAPI) -> Endpoint)?) { 18 | // self.provider = Self.consProvider(isStub, sampleStatusCode, customEndpointClosure) 19 | // } 20 | // 21 | // func fetch(endpoint: NetworkAPI, for type: Model.Type) -> Single where Model : Decodable { 22 | // return .create { observer in 23 | // observer(.success()) 24 | // return Disposables.create() 25 | // } 26 | // self.provider.rx.request(.searchUser(query: "hansangjin96")) 27 | // } 28 | //} 29 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleTests/Mock/MockSearchService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MockSearchService.swift 3 | // SwinjectReactorKitExampleTests 4 | // 5 | // Created by 한상진 on 2021/06/16. 6 | // 7 | 8 | import Foundation 9 | import Moya 10 | import RxSwift 11 | 12 | @testable import SwinjectReactorKitExample 13 | 14 | final class MockSearchService: SearchServiceType { 15 | // 이거만 Mock화 하면 됨 16 | func searchUser(id: String) -> Observable { 17 | 18 | if self.isError { 19 | return Observable.error(ImageDownloadError.dataError) 20 | } else if self.responseIsNil { 21 | return Observable.just( 22 | SearchUserResult( 23 | nickname: nil, 24 | urlData: Data("test data".utf8), 25 | id: nil 26 | ) 27 | ) 28 | } else { 29 | return Observable.just( 30 | SearchUserResult( 31 | nickname: "hansangjin96", 32 | urlData: Data("test data".utf8), 33 | id: 57659933 34 | ) 35 | ) 36 | } 37 | } 38 | 39 | var provider: MoyaProvider = .init() 40 | 41 | let isError: Bool 42 | let responseIsNil: Bool 43 | 44 | init( 45 | isError: Bool = false, 46 | responseIsNil: Bool = false 47 | ) { 48 | self.isError = isError 49 | self.responseIsNil = responseIsNil 50 | } 51 | 52 | init(isStub: Bool, sampleStatusCode: Int, customEndpointClosure: ((NetworkAPI) -> Endpoint)?, imageService: ImageServiceType) { 53 | self.isError = false 54 | self.responseIsNil = false 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleTests/Mock/MockURLSession.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MockURLSession.swift 3 | // SwinjectReactorKitExampleTests 4 | // 5 | // Created by 홍경표 on 2021/06/15. 6 | // 7 | 8 | @testable import SwinjectReactorKitExample 9 | import Foundation 10 | 11 | class MockURLSessionDataTask: URLSessionDataTask { 12 | override init() { } 13 | var resumeDidCall: () -> Void = { } 14 | 15 | override func resume() { 16 | resumeDidCall() 17 | } 18 | 19 | override func cancel() { 20 | print("MockURLSessionDataTask Cancelled!") 21 | } 22 | } 23 | 24 | class MockURLSession: URLSessionType { 25 | 26 | var makeRequestFail = false 27 | init(makeRequestFail: Bool = false) { 28 | self.makeRequestFail = makeRequestFail 29 | } 30 | 31 | var sessionDataTask: MockURLSessionDataTask? 32 | 33 | func dataTask(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask { 34 | 35 | let successResponse = HTTPURLResponse( 36 | url: NetworkAPI.baseURLForTest, 37 | statusCode: 200, 38 | httpVersion: "2", 39 | headerFields: nil 40 | ) 41 | 42 | let failureResponse = HTTPURLResponse( 43 | url: NetworkAPI.baseURLForTest, 44 | statusCode: 410, 45 | httpVersion: "2", 46 | headerFields: nil 47 | ) 48 | 49 | let sessionDataTask = MockURLSessionDataTask() 50 | 51 | sessionDataTask.resumeDidCall = { 52 | if self.makeRequestFail { 53 | completionHandler(nil, failureResponse, nil) 54 | } else { 55 | completionHandler(NetworkAPI.sampleDataForTest, successResponse, nil) 56 | } 57 | } 58 | self.sessionDataTask = sessionDataTask 59 | return sessionDataTask 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleTests/PresentationTest/SearchReactorTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchReactorTest.swift 3 | // SwinjectReactorKitExampleTests 4 | // 5 | // Created by 한상진 on 2021/06/16. 6 | // 7 | 8 | import Foundation 9 | import Quick 10 | import Nimble 11 | import ReactorKit 12 | 13 | @testable import SwinjectReactorKitExample 14 | 15 | // Action을 받았을 때 State로 잘 변경되는지 테스트 16 | final class SearchReactorTest: QuickSpec { 17 | override func spec() { 18 | describe("seachUser Action이 들어왔을 때") { 19 | let container = DIContainer.shared.getContainter() 20 | container.register(Bool.self, name: "isStub") { resolver in 21 | return true 22 | } 23 | 24 | var reactor: SearchReactor! 25 | 26 | context("서버에서 정상적인 값을 받았을 때") { 27 | beforeEach { 28 | container.register(SearchServiceType.self, name: "stub") { resolver in 29 | MockSearchService() 30 | } 31 | 32 | reactor = SearchReactor() 33 | reactor.action.onNext(.searchUser(id: "hansangjin96")) 34 | } 35 | 36 | it("search state가 정상적으로 바뀐다.") { 37 | expect(reactor.currentState.searchResult).to(equal("hansangjin96")) 38 | expect(reactor.currentState.searchIDResult).to(equal("57659933")) 39 | expect(reactor.currentState.searchAvartarImageData).to(equal(Data("test data".utf8))) 40 | } 41 | } 42 | 43 | context("Mutation에서 catchError했을 때") { 44 | beforeEach { 45 | container.register(SearchServiceType.self, name: "stub") { resolver in 46 | MockSearchService(isError: true) 47 | } 48 | 49 | reactor = SearchReactor() 50 | reactor.action.onNext(.searchUser(id: "hansangjin96")) 51 | } 52 | 53 | it("search state가 바뀌지 않고 initialState가 나온다.") { 54 | expect(reactor.currentState.searchResult).to(equal(reactor.initialState.searchResult)) 55 | expect(reactor.currentState.searchIDResult).to(equal(reactor.initialState.searchIDResult)) 56 | expect(reactor.currentState.searchAvartarImageData).to(beNil()) 57 | 58 | } 59 | } 60 | 61 | context("서버에서 Nil값을 받았을 때") { 62 | beforeEach { 63 | container.register(SearchServiceType.self, name: "stub") { resolver in 64 | MockSearchService(responseIsNil: true) 65 | } 66 | 67 | reactor = SearchReactor() 68 | reactor.action.onNext(.searchUser(id: "hansangjin96")) 69 | } 70 | it("search state가 default value로 바뀐다.") { 71 | expect(reactor.currentState.searchResult).to(equal("없음")) 72 | expect(reactor.currentState.searchIDResult).to(equal("0")) 73 | expect(reactor.currentState.searchAvartarImageData).to(equal(Data("test data".utf8))) 74 | } 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleTests/RepositoryTest/NetworkRepositoryTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkRepositoryTesty.swift 3 | // SwinjectReactorKitExampleTests 4 | // 5 | // Created by 한상진 on 2021/06/17. 6 | // 7 | 8 | import Foundation 9 | 10 | import Quick 11 | import Nimble 12 | import RxSwift 13 | import RxNimble 14 | import Moya 15 | 16 | @testable import SwinjectReactorKitExample 17 | 18 | class NetworkRepositoryTest: QuickSpec { 19 | override func spec() { 20 | describe("네트워크가 정상이고") { 21 | var repo: NetworkRepositoryType! 22 | var result: User! 23 | context("유저를 검색해서 정상 결과를 받으면") { 24 | beforeEach { 25 | repo = NetworkRepository(isStub: true) 26 | result = try! repo.fetch(endpoint: .searchUser(query: ""), for: User.self).toBlocking().first() 27 | } 28 | it("샘플데이터와 같은 User를 받는다.") { 29 | 30 | let encoded = try! JSONEncoder().encode(result) 31 | let expected = NetworkAPI.searchUser(query: "").sampleData 32 | 33 | expect(encoded).to(equal(expected)) 34 | } 35 | } 36 | 37 | context("response가 successful status code 범위를 벗어나면") { 38 | beforeEach { 39 | repo = NetworkRepository(isStub: true, sampleStatusCode: 404) 40 | } 41 | it("MoyaError가 나온다.") { 42 | do { 43 | result = try repo.fetch(endpoint: .searchUser(query: ""), for: User.self).toBlocking().first() 44 | XCTFail() 45 | } catch { 46 | let expected = error as! MoyaError 47 | expect(expected.response!.statusCode).to(equal(404)) 48 | } 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleTests/RepositoryTest/URLSessionTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageServiceTest.swift 3 | // SwinjectReactorKitExampleTests 4 | // 5 | // Created by 한상진 on 2021/06/14. 6 | // 7 | 8 | import XCTest 9 | import RxSwift 10 | import RxTest 11 | import Nimble 12 | import RxNimble 13 | import Swinject 14 | 15 | @testable import SwinjectReactorKitExample 16 | 17 | class URLSessionTest: XCTestCase { 18 | 19 | var sut: ImageService! 20 | var container: Container! 21 | 22 | override func setUpWithError() throws { 23 | self.container = DIContainer.shared.getContainter() 24 | container.register(Bool.self, name: "isStub") { resolver in 25 | return true 26 | } 27 | } 28 | 29 | func test_네트워크_통신_성공_200_sampleData() { 30 | 31 | container.register(URLSessionType.self, name: "stub") { resolver in 32 | MockURLSession() 33 | } 34 | 35 | sut = .init() 36 | 37 | let expectation = XCTestExpectation() 38 | 39 | let response = NetworkAPI.sampleDataForTest 40 | 41 | sut.fetchData(url: NetworkAPI.baseURLForTest) { result in 42 | switch result { 43 | case .success(let data): 44 | XCTAssertEqual(data, response) 45 | 46 | case .failure: 47 | XCTFail() 48 | } 49 | 50 | expectation.fulfill() 51 | } 52 | 53 | wait(for: [expectation], timeout: 2.0) 54 | } 55 | 56 | func test_네트워크_통신_실패_410_statusError() { 57 | container.register(URLSessionType.self, name: "stub") { resolver in 58 | MockURLSession(makeRequestFail: true) 59 | } 60 | 61 | sut = .init() 62 | 63 | let expectation = XCTestExpectation() 64 | 65 | let expectedError = ImageDownloadError.statusError 66 | 67 | sut.fetchData(url: NetworkAPI.baseURLForTest) { result in 68 | switch result { 69 | case .success: 70 | XCTFail() 71 | 72 | case .failure(let error): 73 | XCTAssertEqual(error, expectedError) 74 | } 75 | expectation.fulfill() 76 | } 77 | 78 | wait(for: [expectation], timeout: 2.0) 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleTests/ServiceTest/ImageServiceTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageServiceTest.swift 3 | // SwinjectReactorKitExampleTests 4 | // 5 | // Created by 한상진 on 2021/06/14. 6 | // 7 | 8 | import XCTest 9 | import RxSwift 10 | import RxTest 11 | import Nimble 12 | import RxNimble 13 | import Swinject 14 | 15 | @testable import SwinjectReactorKitExample 16 | 17 | class ImageServiceTest: XCTestCase { 18 | 19 | var sut: ImageService! 20 | var container: Container! 21 | 22 | override func setUpWithError() throws { 23 | self.container = DIContainer.shared.getContainter() 24 | container.register(Bool.self, name: "isStub") { resolver in 25 | return true 26 | } 27 | 28 | container.register(URLSessionType.self, name: "stub") { resolver in 29 | MockURLSession() 30 | } 31 | 32 | sut = .init() 33 | XCTAssertNotNil(sut) 34 | } 35 | 36 | func test_이미지_다운로드_Single_url이_nil일때_성공() { 37 | let expectedResponse = ImageDownloadError.urlError 38 | 39 | // when 40 | // url == nil 41 | do { 42 | _ = try sut.fetchImage(with: nil) 43 | // .catchError { error in 44 | // print("catchedERRR") 45 | // XCTAssertEqual(error as! ImageDownloadError, expectedResponse) 46 | // return .just(nil) 47 | // } 48 | .toBlocking() 49 | .first() 50 | XCTFail("catch에서 error 잡아야함.") 51 | } catch { 52 | // then 53 | // Observable을 catchError 안했을 때, onError로 sequence가 끝날 경우 first() 에서 error throw 54 | XCTAssertEqual(error as! ImageDownloadError, expectedResponse) 55 | } 56 | } 57 | 58 | func test() { 59 | // when 60 | // self == nil 61 | let expectedResponse = ImageDownloadError.selfError 62 | 63 | do { 64 | _ = try sut.fetchImage(with: NetworkAPI.baseURLForTest) 65 | .do(onSubscribe: { [weak self] in 66 | self?.sut = nil 67 | }) 68 | .toBlocking().first() 69 | XCTFail("catch에서 error 잡아야함.") 70 | } catch { 71 | // then 72 | XCTAssertEqual(expectedResponse, error as! ImageDownloadError) 73 | } 74 | } 75 | 76 | func test2() { 77 | let expectedResult = NetworkAPI.sampleDataForTest 78 | // when 79 | // 정상 url 80 | do { 81 | let result = try sut.fetchImage(with: NetworkAPI.baseURLForTest) 82 | .toBlocking().first() 83 | 84 | // then 85 | XCTAssertEqual(expectedResult, result) 86 | } catch { 87 | XCTFail("try 문에서 error throw하면 안됨") 88 | } 89 | } 90 | } 91 | 92 | // MARK: 연습용 93 | 94 | extension ImageServiceTest { 95 | 96 | func test_RxTest_연습1() { 97 | let someObservable = Observable.of(10, 20, 30) 98 | let result = try! someObservable.toBlocking().first() 99 | XCTAssertEqual(result, 10) 100 | 101 | let scheduler = ConcurrentDispatchQueueScheduler(qos: .background) 102 | let intObservable = Observable.of(10, 20, 30) 103 | .map { $0 * 2 } 104 | .subscribeOn(scheduler) 105 | do { 106 | let result = try intObservable.observeOn(MainScheduler.instance).toBlocking().toArray() 107 | XCTAssertEqual(result, [20, 40, 60]) 108 | } catch { 109 | XCTFail(error.localizedDescription) 110 | } 111 | } 112 | 113 | func test_RxTest_연습2() { 114 | let scheduler = TestScheduler(initialClock: 0) 115 | 116 | let xs = scheduler.createHotObservable([ 117 | Recorded.next(150, 1), 118 | Recorded.next(210, 0), 119 | Recorded.next(220, 1), 120 | Recorded.next(230, 2), 121 | Recorded.next(240, 4), 122 | Recorded.completed(300) 123 | ]) 124 | 125 | let res = scheduler.start { xs.map { $0 * 2 } } 126 | 127 | let correctMessages = [ 128 | Recorded.next(210, 0 * 2), 129 | Recorded.next(220, 1 * 2), 130 | Recorded.next(230, 2 * 2), 131 | Recorded.next(240, 4 * 2), 132 | Recorded.completed(300) 133 | ] 134 | 135 | let correctSubscriptions = [ 136 | Subscription(200, 300) 137 | ] 138 | 139 | XCTAssertEqual(res.events, correctMessages) 140 | XCTAssertEqual(xs.subscriptions, correctSubscriptions) 141 | } 142 | 143 | 144 | } 145 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleTests/ServiceTest/SearchServiceTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchServiceTest.swift 3 | // SwinjectReactorKitExampleTests 4 | // 5 | // Created by 한상진 on 2021/06/16. 6 | // 7 | 8 | import XCTest 9 | import Quick 10 | import Nimble 11 | import Moya 12 | 13 | @testable import SwinjectReactorKitExample 14 | 15 | class SearchServiceTest: QuickSpec { 16 | 17 | override func spec() { 18 | 19 | // given 20 | describe("SearchService searchUser 했을 때") { 21 | let container = DIContainer.shared.getContainter() 22 | container.register(Bool.self, name: "isStub") { resolver in 23 | return true 24 | } 25 | 26 | var sut: SearchService! 27 | var result: SearchUserResult! 28 | 29 | // when 30 | context("정상 입력") { 31 | beforeEach { 32 | container.register(ImageServiceType.self, name: "stub") { resolver in 33 | MockImageService() 34 | } 35 | container.register(NetworkRepositoryType.self, name: "stub") { resolver in 36 | NetworkRepository(isStub: true) 37 | } 38 | sut = SearchService() 39 | result = try! sut.searchUser(id: "hansangjin96").toBlocking().first() 40 | } 41 | 42 | it("정상 출력") { 43 | let expected = SearchUserResult(nickname: "hansangjin96", urlData: Data("test".utf8), id: 57659933) 44 | expect(result).to(equal(expected)) 45 | } 46 | } 47 | 48 | context("잘못된 입력") { 49 | beforeEach { 50 | container.register(ImageServiceType.self, name: "stub") { resolver in 51 | MockImageService(makeRequestFail: true) 52 | } 53 | container.register(NetworkRepositoryType.self, name: "stub") { resolver in 54 | NetworkRepository(isStub: true) 55 | } 56 | sut = SearchService() 57 | result = try! sut.searchUser(id: "hansangjin96").toBlocking().first() 58 | } 59 | 60 | it("에러 출력") { 61 | let expectedResult = SearchUserResult(nickname: "hansangjin96", urlData: nil, id: 57659933) 62 | expect(result).to(equal(expectedResult)) 63 | } 64 | } 65 | 66 | } 67 | } 68 | 69 | // override func spec() { 70 | // // given: 설명하려는 동작 71 | // describe("SearchService searchUser 했을 때") { 72 | // 73 | // // when: 해당 동작 74 | // context("잘못된 입력이면") { 75 | // var sut: SearchService! 76 | // var result: SearchUserResult! 77 | // 78 | // beforeEach { 79 | // let imageServiceMock = MockImageService(makeRequestFail: true) 80 | // // sut: system under test 81 | // sut = SearchService( 82 | // isStub: true, 83 | // imageService: imageServiceMock 84 | // ) 85 | // result = try! sut.searchUser(id: "Hansangjin96") 86 | // .toBlocking() 87 | // .first() 88 | // } 89 | // 90 | // // then: 발생할 것으로 예상되는 동작 91 | // it("에러가 나온다.") { 92 | // let expectedResult = SearchUserResult(nickname: "hansangjin96", urlData: nil, id: 57659933) 93 | // expect(result).to(equal(expectedResult)) 94 | // } 95 | // } 96 | // 97 | // // when: 해당 동작 98 | // context("정상적이면(?)") { 99 | // var sut: SearchService! 100 | // var result: SearchUserResult! 101 | // 102 | // beforeEach { 103 | // let imageServiceMock = MockImageService() 104 | // // sut: system under test 105 | // sut = SearchService( 106 | // isStub: true, 107 | // imageService: imageServiceMock 108 | // ) 109 | // result = try! sut.searchUser(id: "Hansangjin96") 110 | // .toBlocking() 111 | // .first() 112 | // } 113 | // 114 | // // then: 발생할 것으로 예상되는 동작 115 | // it("SearchUserResult가 나온다.") { 116 | // let expectedResult = SearchUserResult(nickname: "hansangjin96", urlData: Data("test".utf8), id: 57659933) 117 | // expect(result).to(equal(expectedResult)) 118 | // } 119 | // } 120 | // } 121 | // } 122 | } 123 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SwinjectReactorKitExampleUITests/SwinjectReactorKitExampleUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwinjectReactorKitExampleUITests.swift 3 | // SwinjectReactorKitExampleUITests 4 | // 5 | // Created by 한상진 on 2021/05/21. 6 | // 7 | 8 | import XCTest 9 | 10 | class SwinjectReactorKitExampleUITests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | 15 | // In UI tests it is usually best to stop immediately when a failure occurs. 16 | continueAfterFailure = false 17 | 18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 19 | } 20 | 21 | override func tearDownWithError() throws { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | func testExample() throws { 26 | // UI tests must launch the application that they test. 27 | let app = XCUIApplication() 28 | app.launch() 29 | 30 | // Use recording to get started writing UI tests. 31 | // Use XCTAssert and related functions to verify your tests produce the correct results. 32 | } 33 | 34 | func testLaunchPerformance() throws { 35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { 36 | // This measures how long it takes to launch your application. 37 | measure(metrics: [XCTApplicationLaunchMetric()]) { 38 | XCUIApplication().launch() 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Tuist/Config.swift: -------------------------------------------------------------------------------- 1 | import ProjectDescription 2 | 3 | let config = Config( 4 | generationOptions: [] 5 | ) 6 | -------------------------------------------------------------------------------- /Tuist/ProjectDescriptionHelpers/Project+Templates.swift: -------------------------------------------------------------------------------- 1 | import ProjectDescription 2 | 3 | /// Project helpers are functions that simplify the way you define your project. 4 | /// Share code to create targets, settings, dependencies, 5 | /// Create your own conventions, e.g: a func that makes sure all shared targets are "static frameworks" 6 | /// See https://docs.tuist.io/guides/helpers/ 7 | 8 | extension Project { 9 | /// Helper function to create the Project for this ExampleApp 10 | public static func app(name: String, platform: Platform, additionalTargets: [String]) -> Project { 11 | var targets = makeAppTargets(name: name, 12 | platform: platform, 13 | dependencies: additionalTargets.map { TargetDependency.target(name: $0) }) 14 | targets += additionalTargets.flatMap({ makeFrameworkTargets(name: $0, platform: platform) }) 15 | return Project(name: name, 16 | organizationName: "tuist.io", 17 | targets: targets) 18 | } 19 | 20 | // MARK: - Private 21 | 22 | /// Helper function to create a framework target and an associated unit test target 23 | private static func makeFrameworkTargets(name: String, platform: Platform) -> [Target] { 24 | let sources = Target(name: name, 25 | platform: platform, 26 | product: .framework, 27 | bundleId: "io.tuist.\(name)", 28 | infoPlist: .default, 29 | sources: ["Targets/\(name)/Sources/**"], 30 | resources: [], 31 | dependencies: []) 32 | let tests = Target(name: "\(name)Tests", 33 | platform: platform, 34 | product: .unitTests, 35 | bundleId: "io.tuist.\(name)Tests", 36 | infoPlist: .default, 37 | sources: ["Targets/\(name)/Tests/**"], 38 | resources: [], 39 | dependencies: [.target(name: name)]) 40 | return [sources, tests] 41 | } 42 | 43 | /// Helper function to create the application target and the unit test target. 44 | private static func makeAppTargets(name: String, platform: Platform, dependencies: [TargetDependency]) -> [Target] { 45 | let platform: Platform = platform 46 | let infoPlist: [String: InfoPlist.Value] = [ 47 | "CFBundleShortVersionString": "1.0", 48 | "CFBundleVersion": "1", 49 | "UIMainStoryboardFile": "", 50 | "UILaunchStoryboardName": "LaunchScreen" 51 | ] 52 | 53 | let mainTarget = Target( 54 | name: name, 55 | platform: platform, 56 | product: .app, 57 | bundleId: "io.tuist.\(name)", 58 | infoPlist: .extendingDefault(with: infoPlist), 59 | sources: ["Targets/\(name)/Sources/**"], 60 | resources: ["Targets/\(name)/Resources/**"], 61 | dependencies: dependencies 62 | ) 63 | 64 | let testTarget = Target( 65 | name: "\(name)Tests", 66 | platform: platform, 67 | product: .unitTests, 68 | bundleId: "io.tuist.\(name)Tests", 69 | infoPlist: .default, 70 | sources: ["Targets/\(name)/Tests/**"], 71 | dependencies: [ 72 | .target(name: "\(name)") 73 | ]) 74 | return [mainTarget, testTarget] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /project.yml: -------------------------------------------------------------------------------- 1 | name: SwinjectReactorKitExample 2 | 3 | attributes: 4 | ORGANIZATIONNAME: havi 5 | 6 | options: 7 | deploymentTarget: 8 | iOS: 14.5 9 | defaultConfig: Release 10 | indentWidth: 4 11 | tabWidth: 4 12 | 13 | postGenCommand: pod install 14 | 15 | targets: 16 | SwinjectReactorKitExample: 17 | type: application 18 | platform: iOS 19 | sources: [SwinjectReactorKitExample] 20 | 21 | preBuildScripts: 22 | - name: R.swift 23 | script: | 24 | "echo R.swift" 25 | settings: 26 | base: 27 | INFOPLIST_FILE: SwinjectReactorKitExample/Supporting/Info.plist 28 | PRODUCT_BUNDLE_IDENTIFIER: com.havi.SwinjectReactorKitExample 29 | 30 | SwinjectReactorKitExampleTests: 31 | type: bundle.unit-test 32 | platform: iOS 33 | settings: 34 | base: 35 | INFOPLIST_FILE: SwinjectReactorKitExampleTests/Info.plist 36 | PRODUCT_BUNDLE_IDENTIFIER: com.havi.SwinjectReactorKitExampleTests 37 | sources: [SwinjectReactorKitExampleTests] 38 | 39 | 40 | SwinjectReactorKitExampleUITests: 41 | type: bundle.ui-testing 42 | platform: iOS 43 | settings: 44 | base: 45 | INFOPLIST_FILE: SwinjectReactorKitExampleUITests/Info.plist 46 | PRODUCT_BUNDLE_IDENTIFIER: com.havi.SwinjectReactorKitExampleUITests 47 | sources: [SwinjectReactorKitExampleUITests] 48 | --------------------------------------------------------------------------------