├── .DS_Store ├── .gitignore ├── AppDelegate.swift ├── Core ├── .DS_Store ├── Core.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ └── oguzparlak.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── Core │ ├── .DS_Store │ ├── Coordinator │ │ ├── ConcreteCoordinator.swift │ │ ├── Coordinator.swift │ │ └── Storyboarded.swift │ ├── Core.h │ ├── Data │ │ ├── DataManager.swift │ │ ├── DataNotifier.swift │ │ └── KeyValueManager.swift │ ├── Extensions │ │ └── UI │ │ │ ├── UIDevice+.swift │ │ │ ├── UINavigationController+.swift │ │ │ └── UIView+.swift │ ├── Info.plist │ ├── Repository │ │ └── Repository.swift │ └── UI │ │ └── .DS_Store └── CoreTests │ ├── CoreTests.swift │ └── Info.plist ├── MVVM-C-App-Core-Networking.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── oguzparlak.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── oguzparlak.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── MVVM-C-App-Core-Networking.xcworkspace ├── contents.xcworkspacedata ├── xcshareddata │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── oguzparlak.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── MVVM-C-App-Core-Networking ├── .DS_Store ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── color_dark_bg.colorset │ │ └── Contents.json │ ├── color_theme.colorset │ │ └── Contents.json │ ├── ic_popular.imageset │ │ ├── Contents.json │ │ ├── icons8-tv-show-100.png │ │ ├── icons8-tv-show-100@2x.png │ │ └── icons8-tv-show-100@3x.png │ ├── ic_popular_disabled.imageset │ │ ├── Contents.json │ │ ├── icons8-tv-show-100.png │ │ ├── icons8-tv-show-100@2x.png │ │ └── icons8-tv-show-100@3x.png │ └── ic_star.imageset │ │ ├── Contents.json │ │ ├── icons8-star-90.png │ │ ├── icons8-star-90@2x.png │ │ └── icons8-star-90@3x.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Coordinator │ └── TVShowListingCoordinator.swift ├── Data │ └── TVShowDataManager.swift ├── Extension │ ├── TVShowListView+UITableViewDelegate.swift │ ├── TVShowListingView+TVShowInteractor.swift │ ├── TVShowListingView+UITableViewDataSource.swift │ └── TVShowListingView+UITableViewDataSourcePrefetching.swift ├── Info.plist ├── Interactor │ └── TVShowInteractor.swift ├── Model │ ├── TVShow.swift │ └── TVShowContainer.swift ├── Networking │ └── TVShowEndPoint.swift ├── Repository │ └── TVShowRepository.swift ├── View │ ├── MovieListingCell.swift │ ├── MovieListingCell.xib │ └── TVShowListingView.swift └── ViewModel │ ├── TVShowCellViewModel.swift │ └── TVShowViewModel.swift ├── Networking ├── .DS_Store ├── Networking.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ └── oguzparlak.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── Networking │ ├── ApiClient.swift │ ├── ApiError.swift │ ├── ApiRouter.swift │ ├── Constants.swift │ ├── EndpointProvider.swift │ ├── Info.plist │ ├── Networking.h │ ├── Reachability.swift │ └── RequestConfigurator.swift └── NetworkingTests │ ├── Info.plist │ └── NetworkingTests.swift ├── Podfile ├── Podfile.lock ├── README.md └── Root └── RootController.swift /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | Pods/ 50 | # 51 | # Add this line if you want to avoid checking in source code from the Xcode workspace 52 | # *.xcworkspace 53 | 54 | # Carthage 55 | # 56 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 57 | # Carthage/Checkouts 58 | 59 | Carthage/Build 60 | 61 | # Accio dependency management 62 | Dependencies/ 63 | .accio/ 64 | 65 | # fastlane 66 | # 67 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 68 | # screenshots whenever they are needed. 69 | # For more information about the recommended setup visit: 70 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 71 | 72 | fastlane/report.xml 73 | fastlane/Preview.html 74 | fastlane/screenshots/**/*.png 75 | fastlane/test_output 76 | 77 | # Code Injection 78 | # 79 | # After new code Injection tools there's a generated folder /iOSInjectionProject 80 | # https://github.com/johnno1962/injectionforxcode 81 | 82 | iOSInjectionProject/ -------------------------------------------------------------------------------- /AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | 19 | window = UIWindow(frame: UIScreen.main.bounds) 20 | window?.makeKeyAndVisible() 21 | window?.rootViewController = RootController() 22 | 23 | return true 24 | } 25 | 26 | func applicationWillResignActive(_ application: UIApplication) { 27 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 28 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 29 | } 30 | 31 | func applicationDidEnterBackground(_ application: UIApplication) { 32 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 33 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 34 | } 35 | 36 | func applicationWillEnterForeground(_ application: UIApplication) { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | func applicationDidBecomeActive(_ application: UIApplication) { 41 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 42 | } 43 | 44 | func applicationWillTerminate(_ application: UIApplication) { 45 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 46 | } 47 | 48 | 49 | } 50 | 51 | -------------------------------------------------------------------------------- /Core/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/Core/.DS_Store -------------------------------------------------------------------------------- /Core/Core.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BF014FEC22CE8245006669CD /* Networking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF014FEB22CE8245006669CD /* Networking.framework */; }; 11 | BF5EC47022C52A080068A24C /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF5EC46622C52A080068A24C /* Core.framework */; }; 12 | BF5EC47522C52A080068A24C /* CoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC47422C52A080068A24C /* CoreTests.swift */; }; 13 | BF5EC47722C52A080068A24C /* Core.h in Headers */ = {isa = PBXBuildFile; fileRef = BF5EC46922C52A080068A24C /* Core.h */; settings = {ATTRIBUTES = (Public, ); }; }; 14 | BF5EC49822C560850068A24C /* DataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC49722C560850068A24C /* DataManager.swift */; }; 15 | BF5EC49A22C561A90068A24C /* KeyValueManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC49922C561A90068A24C /* KeyValueManager.swift */; }; 16 | BF5EC49C22C561EA0068A24C /* DataNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC49B22C561EA0068A24C /* DataNotifier.swift */; }; 17 | BF5EC4A022C562380068A24C /* Repository.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC49F22C562380068A24C /* Repository.swift */; }; 18 | BF5EC4A322C562B40068A24C /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC4A222C562B40068A24C /* Coordinator.swift */; }; 19 | BF5EC4A522C562E70068A24C /* Storyboarded.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC4A422C562E70068A24C /* Storyboarded.swift */; }; 20 | BF5EC4A722C563550068A24C /* ConcreteCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC4A622C563550068A24C /* ConcreteCoordinator.swift */; }; 21 | BF5EC4AB22C564410068A24C /* UINavigationController+.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC4AA22C564410068A24C /* UINavigationController+.swift */; }; 22 | BF5EC4AD22C564730068A24C /* UIView+.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC4AC22C564730068A24C /* UIView+.swift */; }; 23 | BF5EC4AF22C564960068A24C /* UIDevice+.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC4AE22C564960068A24C /* UIDevice+.swift */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | BF5EC47122C52A080068A24C /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = BF5EC45D22C52A080068A24C /* Project object */; 30 | proxyType = 1; 31 | remoteGlobalIDString = BF5EC46522C52A080068A24C; 32 | remoteInfo = Core; 33 | }; 34 | /* End PBXContainerItemProxy section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | BF014FEB22CE8245006669CD /* Networking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Networking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | BF5EC46622C52A080068A24C /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | BF5EC46922C52A080068A24C /* Core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Core.h; sourceTree = ""; }; 40 | BF5EC46A22C52A080068A24C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | BF5EC46F22C52A080068A24C /* CoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | BF5EC47422C52A080068A24C /* CoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreTests.swift; sourceTree = ""; }; 43 | BF5EC47622C52A080068A24C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 44 | BF5EC49722C560850068A24C /* DataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataManager.swift; sourceTree = ""; }; 45 | BF5EC49922C561A90068A24C /* KeyValueManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyValueManager.swift; sourceTree = ""; }; 46 | BF5EC49B22C561EA0068A24C /* DataNotifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataNotifier.swift; sourceTree = ""; }; 47 | BF5EC49F22C562380068A24C /* Repository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Repository.swift; sourceTree = ""; }; 48 | BF5EC4A222C562B40068A24C /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = ""; }; 49 | BF5EC4A422C562E70068A24C /* Storyboarded.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storyboarded.swift; sourceTree = ""; }; 50 | BF5EC4A622C563550068A24C /* ConcreteCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcreteCoordinator.swift; sourceTree = ""; }; 51 | BF5EC4AA22C564410068A24C /* UINavigationController+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+.swift"; sourceTree = ""; }; 52 | BF5EC4AC22C564730068A24C /* UIView+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+.swift"; sourceTree = ""; }; 53 | BF5EC4AE22C564960068A24C /* UIDevice+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+.swift"; sourceTree = ""; }; 54 | /* End PBXFileReference section */ 55 | 56 | /* Begin PBXFrameworksBuildPhase section */ 57 | BF5EC46322C52A080068A24C /* Frameworks */ = { 58 | isa = PBXFrameworksBuildPhase; 59 | buildActionMask = 2147483647; 60 | files = ( 61 | BF014FEC22CE8245006669CD /* Networking.framework in Frameworks */, 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | BF5EC46C22C52A080068A24C /* Frameworks */ = { 66 | isa = PBXFrameworksBuildPhase; 67 | buildActionMask = 2147483647; 68 | files = ( 69 | BF5EC47022C52A080068A24C /* Core.framework in Frameworks */, 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | /* End PBXFrameworksBuildPhase section */ 74 | 75 | /* Begin PBXGroup section */ 76 | BF014FEA22CE8245006669CD /* Frameworks */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | BF014FEB22CE8245006669CD /* Networking.framework */, 80 | ); 81 | name = Frameworks; 82 | sourceTree = ""; 83 | }; 84 | BF5EC45C22C52A080068A24C = { 85 | isa = PBXGroup; 86 | children = ( 87 | BF5EC46822C52A080068A24C /* Core */, 88 | BF5EC47322C52A080068A24C /* CoreTests */, 89 | BF5EC46722C52A080068A24C /* Products */, 90 | BF014FEA22CE8245006669CD /* Frameworks */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | BF5EC46722C52A080068A24C /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | BF5EC46622C52A080068A24C /* Core.framework */, 98 | BF5EC46F22C52A080068A24C /* CoreTests.xctest */, 99 | ); 100 | name = Products; 101 | sourceTree = ""; 102 | }; 103 | BF5EC46822C52A080068A24C /* Core */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | BF5EC4B022C564BA0068A24C /* UI */, 107 | BF5EC4A822C564130068A24C /* Extensions */, 108 | BF5EC4A122C562A70068A24C /* Coordinator */, 109 | BF5EC49E22C562260068A24C /* Repository */, 110 | BF5EC49D22C5621E0068A24C /* Data */, 111 | BF5EC46922C52A080068A24C /* Core.h */, 112 | BF5EC46A22C52A080068A24C /* Info.plist */, 113 | ); 114 | path = Core; 115 | sourceTree = ""; 116 | }; 117 | BF5EC47322C52A080068A24C /* CoreTests */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | BF5EC47422C52A080068A24C /* CoreTests.swift */, 121 | BF5EC47622C52A080068A24C /* Info.plist */, 122 | ); 123 | path = CoreTests; 124 | sourceTree = ""; 125 | }; 126 | BF5EC49D22C5621E0068A24C /* Data */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | BF5EC49722C560850068A24C /* DataManager.swift */, 130 | BF5EC49922C561A90068A24C /* KeyValueManager.swift */, 131 | BF5EC49B22C561EA0068A24C /* DataNotifier.swift */, 132 | ); 133 | path = Data; 134 | sourceTree = ""; 135 | }; 136 | BF5EC49E22C562260068A24C /* Repository */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | BF5EC49F22C562380068A24C /* Repository.swift */, 140 | ); 141 | path = Repository; 142 | sourceTree = ""; 143 | }; 144 | BF5EC4A122C562A70068A24C /* Coordinator */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | BF5EC4A222C562B40068A24C /* Coordinator.swift */, 148 | BF5EC4A422C562E70068A24C /* Storyboarded.swift */, 149 | BF5EC4A622C563550068A24C /* ConcreteCoordinator.swift */, 150 | ); 151 | path = Coordinator; 152 | sourceTree = ""; 153 | }; 154 | BF5EC4A822C564130068A24C /* Extensions */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | BF5EC4A922C564260068A24C /* UI */, 158 | ); 159 | path = Extensions; 160 | sourceTree = ""; 161 | }; 162 | BF5EC4A922C564260068A24C /* UI */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | BF5EC4AA22C564410068A24C /* UINavigationController+.swift */, 166 | BF5EC4AC22C564730068A24C /* UIView+.swift */, 167 | BF5EC4AE22C564960068A24C /* UIDevice+.swift */, 168 | ); 169 | path = UI; 170 | sourceTree = ""; 171 | }; 172 | BF5EC4B022C564BA0068A24C /* UI */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | ); 176 | path = UI; 177 | sourceTree = ""; 178 | }; 179 | /* End PBXGroup section */ 180 | 181 | /* Begin PBXHeadersBuildPhase section */ 182 | BF5EC46122C52A080068A24C /* Headers */ = { 183 | isa = PBXHeadersBuildPhase; 184 | buildActionMask = 2147483647; 185 | files = ( 186 | BF5EC47722C52A080068A24C /* Core.h in Headers */, 187 | ); 188 | runOnlyForDeploymentPostprocessing = 0; 189 | }; 190 | /* End PBXHeadersBuildPhase section */ 191 | 192 | /* Begin PBXNativeTarget section */ 193 | BF5EC46522C52A080068A24C /* Core */ = { 194 | isa = PBXNativeTarget; 195 | buildConfigurationList = BF5EC47A22C52A080068A24C /* Build configuration list for PBXNativeTarget "Core" */; 196 | buildPhases = ( 197 | BF5EC46122C52A080068A24C /* Headers */, 198 | BF5EC46222C52A080068A24C /* Sources */, 199 | BF5EC46322C52A080068A24C /* Frameworks */, 200 | BF5EC46422C52A080068A24C /* Resources */, 201 | ); 202 | buildRules = ( 203 | ); 204 | dependencies = ( 205 | ); 206 | name = Core; 207 | productName = Core; 208 | productReference = BF5EC46622C52A080068A24C /* Core.framework */; 209 | productType = "com.apple.product-type.framework"; 210 | }; 211 | BF5EC46E22C52A080068A24C /* CoreTests */ = { 212 | isa = PBXNativeTarget; 213 | buildConfigurationList = BF5EC47D22C52A080068A24C /* Build configuration list for PBXNativeTarget "CoreTests" */; 214 | buildPhases = ( 215 | BF5EC46B22C52A080068A24C /* Sources */, 216 | BF5EC46C22C52A080068A24C /* Frameworks */, 217 | BF5EC46D22C52A080068A24C /* Resources */, 218 | ); 219 | buildRules = ( 220 | ); 221 | dependencies = ( 222 | BF5EC47222C52A080068A24C /* PBXTargetDependency */, 223 | ); 224 | name = CoreTests; 225 | productName = CoreTests; 226 | productReference = BF5EC46F22C52A080068A24C /* CoreTests.xctest */; 227 | productType = "com.apple.product-type.bundle.unit-test"; 228 | }; 229 | /* End PBXNativeTarget section */ 230 | 231 | /* Begin PBXProject section */ 232 | BF5EC45D22C52A080068A24C /* Project object */ = { 233 | isa = PBXProject; 234 | attributes = { 235 | LastSwiftUpdateCheck = 1020; 236 | LastUpgradeCheck = 1020; 237 | ORGANIZATIONNAME = "Oguz Parlak"; 238 | TargetAttributes = { 239 | BF5EC46522C52A080068A24C = { 240 | CreatedOnToolsVersion = 10.2.1; 241 | LastSwiftMigration = 1020; 242 | }; 243 | BF5EC46E22C52A080068A24C = { 244 | CreatedOnToolsVersion = 10.2.1; 245 | }; 246 | }; 247 | }; 248 | buildConfigurationList = BF5EC46022C52A080068A24C /* Build configuration list for PBXProject "Core" */; 249 | compatibilityVersion = "Xcode 9.3"; 250 | developmentRegion = en; 251 | hasScannedForEncodings = 0; 252 | knownRegions = ( 253 | en, 254 | ); 255 | mainGroup = BF5EC45C22C52A080068A24C; 256 | productRefGroup = BF5EC46722C52A080068A24C /* Products */; 257 | projectDirPath = ""; 258 | projectRoot = ""; 259 | targets = ( 260 | BF5EC46522C52A080068A24C /* Core */, 261 | BF5EC46E22C52A080068A24C /* CoreTests */, 262 | ); 263 | }; 264 | /* End PBXProject section */ 265 | 266 | /* Begin PBXResourcesBuildPhase section */ 267 | BF5EC46422C52A080068A24C /* Resources */ = { 268 | isa = PBXResourcesBuildPhase; 269 | buildActionMask = 2147483647; 270 | files = ( 271 | ); 272 | runOnlyForDeploymentPostprocessing = 0; 273 | }; 274 | BF5EC46D22C52A080068A24C /* Resources */ = { 275 | isa = PBXResourcesBuildPhase; 276 | buildActionMask = 2147483647; 277 | files = ( 278 | ); 279 | runOnlyForDeploymentPostprocessing = 0; 280 | }; 281 | /* End PBXResourcesBuildPhase section */ 282 | 283 | /* Begin PBXSourcesBuildPhase section */ 284 | BF5EC46222C52A080068A24C /* Sources */ = { 285 | isa = PBXSourcesBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | BF5EC49822C560850068A24C /* DataManager.swift in Sources */, 289 | BF5EC4AF22C564960068A24C /* UIDevice+.swift in Sources */, 290 | BF5EC49A22C561A90068A24C /* KeyValueManager.swift in Sources */, 291 | BF5EC4A322C562B40068A24C /* Coordinator.swift in Sources */, 292 | BF5EC49C22C561EA0068A24C /* DataNotifier.swift in Sources */, 293 | BF5EC4A022C562380068A24C /* Repository.swift in Sources */, 294 | BF5EC4AB22C564410068A24C /* UINavigationController+.swift in Sources */, 295 | BF5EC4AD22C564730068A24C /* UIView+.swift in Sources */, 296 | BF5EC4A522C562E70068A24C /* Storyboarded.swift in Sources */, 297 | BF5EC4A722C563550068A24C /* ConcreteCoordinator.swift in Sources */, 298 | ); 299 | runOnlyForDeploymentPostprocessing = 0; 300 | }; 301 | BF5EC46B22C52A080068A24C /* Sources */ = { 302 | isa = PBXSourcesBuildPhase; 303 | buildActionMask = 2147483647; 304 | files = ( 305 | BF5EC47522C52A080068A24C /* CoreTests.swift in Sources */, 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | }; 309 | /* End PBXSourcesBuildPhase section */ 310 | 311 | /* Begin PBXTargetDependency section */ 312 | BF5EC47222C52A080068A24C /* PBXTargetDependency */ = { 313 | isa = PBXTargetDependency; 314 | target = BF5EC46522C52A080068A24C /* Core */; 315 | targetProxy = BF5EC47122C52A080068A24C /* PBXContainerItemProxy */; 316 | }; 317 | /* End PBXTargetDependency section */ 318 | 319 | /* Begin XCBuildConfiguration section */ 320 | BF5EC47822C52A080068A24C /* Debug */ = { 321 | isa = XCBuildConfiguration; 322 | buildSettings = { 323 | ALWAYS_SEARCH_USER_PATHS = NO; 324 | CLANG_ANALYZER_NONNULL = YES; 325 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 326 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 327 | CLANG_CXX_LIBRARY = "libc++"; 328 | CLANG_ENABLE_MODULES = YES; 329 | CLANG_ENABLE_OBJC_ARC = YES; 330 | CLANG_ENABLE_OBJC_WEAK = YES; 331 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 332 | CLANG_WARN_BOOL_CONVERSION = YES; 333 | CLANG_WARN_COMMA = YES; 334 | CLANG_WARN_CONSTANT_CONVERSION = YES; 335 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 336 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 337 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 338 | CLANG_WARN_EMPTY_BODY = YES; 339 | CLANG_WARN_ENUM_CONVERSION = YES; 340 | CLANG_WARN_INFINITE_RECURSION = YES; 341 | CLANG_WARN_INT_CONVERSION = YES; 342 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 343 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 344 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 345 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 346 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 347 | CLANG_WARN_STRICT_PROTOTYPES = YES; 348 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 349 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 350 | CLANG_WARN_UNREACHABLE_CODE = YES; 351 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 352 | CODE_SIGN_IDENTITY = "iPhone Developer"; 353 | COPY_PHASE_STRIP = NO; 354 | CURRENT_PROJECT_VERSION = 1; 355 | DEBUG_INFORMATION_FORMAT = dwarf; 356 | ENABLE_STRICT_OBJC_MSGSEND = YES; 357 | ENABLE_TESTABILITY = YES; 358 | GCC_C_LANGUAGE_STANDARD = gnu11; 359 | GCC_DYNAMIC_NO_PIC = NO; 360 | GCC_NO_COMMON_BLOCKS = YES; 361 | GCC_OPTIMIZATION_LEVEL = 0; 362 | GCC_PREPROCESSOR_DEFINITIONS = ( 363 | "DEBUG=1", 364 | "$(inherited)", 365 | ); 366 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 367 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 368 | GCC_WARN_UNDECLARED_SELECTOR = YES; 369 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 370 | GCC_WARN_UNUSED_FUNCTION = YES; 371 | GCC_WARN_UNUSED_VARIABLE = YES; 372 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 373 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 374 | MTL_FAST_MATH = YES; 375 | ONLY_ACTIVE_ARCH = YES; 376 | SDKROOT = iphoneos; 377 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 378 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 379 | VERSIONING_SYSTEM = "apple-generic"; 380 | VERSION_INFO_PREFIX = ""; 381 | }; 382 | name = Debug; 383 | }; 384 | BF5EC47922C52A080068A24C /* Release */ = { 385 | isa = XCBuildConfiguration; 386 | buildSettings = { 387 | ALWAYS_SEARCH_USER_PATHS = NO; 388 | CLANG_ANALYZER_NONNULL = YES; 389 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 390 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 391 | CLANG_CXX_LIBRARY = "libc++"; 392 | CLANG_ENABLE_MODULES = YES; 393 | CLANG_ENABLE_OBJC_ARC = YES; 394 | CLANG_ENABLE_OBJC_WEAK = YES; 395 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 396 | CLANG_WARN_BOOL_CONVERSION = YES; 397 | CLANG_WARN_COMMA = YES; 398 | CLANG_WARN_CONSTANT_CONVERSION = YES; 399 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 400 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 401 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 402 | CLANG_WARN_EMPTY_BODY = YES; 403 | CLANG_WARN_ENUM_CONVERSION = YES; 404 | CLANG_WARN_INFINITE_RECURSION = YES; 405 | CLANG_WARN_INT_CONVERSION = YES; 406 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 407 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 408 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 409 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 410 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 411 | CLANG_WARN_STRICT_PROTOTYPES = YES; 412 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 413 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 414 | CLANG_WARN_UNREACHABLE_CODE = YES; 415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 416 | CODE_SIGN_IDENTITY = "iPhone Developer"; 417 | COPY_PHASE_STRIP = NO; 418 | CURRENT_PROJECT_VERSION = 1; 419 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 420 | ENABLE_NS_ASSERTIONS = NO; 421 | ENABLE_STRICT_OBJC_MSGSEND = YES; 422 | GCC_C_LANGUAGE_STANDARD = gnu11; 423 | GCC_NO_COMMON_BLOCKS = YES; 424 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 425 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 426 | GCC_WARN_UNDECLARED_SELECTOR = YES; 427 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 428 | GCC_WARN_UNUSED_FUNCTION = YES; 429 | GCC_WARN_UNUSED_VARIABLE = YES; 430 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 431 | MTL_ENABLE_DEBUG_INFO = NO; 432 | MTL_FAST_MATH = YES; 433 | SDKROOT = iphoneos; 434 | SWIFT_COMPILATION_MODE = wholemodule; 435 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 436 | VALIDATE_PRODUCT = YES; 437 | VERSIONING_SYSTEM = "apple-generic"; 438 | VERSION_INFO_PREFIX = ""; 439 | }; 440 | name = Release; 441 | }; 442 | BF5EC47B22C52A080068A24C /* Debug */ = { 443 | isa = XCBuildConfiguration; 444 | buildSettings = { 445 | CLANG_ENABLE_MODULES = YES; 446 | CODE_SIGN_IDENTITY = ""; 447 | CODE_SIGN_STYLE = Automatic; 448 | DEFINES_MODULE = YES; 449 | DEVELOPMENT_TEAM = HL7GD8S24Y; 450 | DYLIB_COMPATIBILITY_VERSION = 1; 451 | DYLIB_CURRENT_VERSION = 1; 452 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 453 | INFOPLIST_FILE = Core/Info.plist; 454 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 455 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 456 | LD_RUNPATH_SEARCH_PATHS = ( 457 | "$(inherited)", 458 | "@executable_path/Frameworks", 459 | "@loader_path/Frameworks", 460 | ); 461 | PRODUCT_BUNDLE_IDENTIFIER = com.oguzparlak.Core; 462 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 463 | SKIP_INSTALL = YES; 464 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 465 | SWIFT_VERSION = 5.0; 466 | TARGETED_DEVICE_FAMILY = "1,2"; 467 | }; 468 | name = Debug; 469 | }; 470 | BF5EC47C22C52A080068A24C /* Release */ = { 471 | isa = XCBuildConfiguration; 472 | buildSettings = { 473 | CLANG_ENABLE_MODULES = YES; 474 | CODE_SIGN_IDENTITY = ""; 475 | CODE_SIGN_STYLE = Automatic; 476 | DEFINES_MODULE = YES; 477 | DEVELOPMENT_TEAM = HL7GD8S24Y; 478 | DYLIB_COMPATIBILITY_VERSION = 1; 479 | DYLIB_CURRENT_VERSION = 1; 480 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 481 | INFOPLIST_FILE = Core/Info.plist; 482 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 483 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 484 | LD_RUNPATH_SEARCH_PATHS = ( 485 | "$(inherited)", 486 | "@executable_path/Frameworks", 487 | "@loader_path/Frameworks", 488 | ); 489 | PRODUCT_BUNDLE_IDENTIFIER = com.oguzparlak.Core; 490 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 491 | SKIP_INSTALL = YES; 492 | SWIFT_VERSION = 5.0; 493 | TARGETED_DEVICE_FAMILY = "1,2"; 494 | }; 495 | name = Release; 496 | }; 497 | BF5EC47E22C52A080068A24C /* Debug */ = { 498 | isa = XCBuildConfiguration; 499 | buildSettings = { 500 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 501 | CODE_SIGN_STYLE = Automatic; 502 | DEVELOPMENT_TEAM = HL7GD8S24Y; 503 | INFOPLIST_FILE = CoreTests/Info.plist; 504 | LD_RUNPATH_SEARCH_PATHS = ( 505 | "$(inherited)", 506 | "@executable_path/Frameworks", 507 | "@loader_path/Frameworks", 508 | ); 509 | PRODUCT_BUNDLE_IDENTIFIER = com.oguzparlak.CoreTests; 510 | PRODUCT_NAME = "$(TARGET_NAME)"; 511 | SWIFT_VERSION = 5.0; 512 | TARGETED_DEVICE_FAMILY = "1,2"; 513 | }; 514 | name = Debug; 515 | }; 516 | BF5EC47F22C52A080068A24C /* Release */ = { 517 | isa = XCBuildConfiguration; 518 | buildSettings = { 519 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 520 | CODE_SIGN_STYLE = Automatic; 521 | DEVELOPMENT_TEAM = HL7GD8S24Y; 522 | INFOPLIST_FILE = CoreTests/Info.plist; 523 | LD_RUNPATH_SEARCH_PATHS = ( 524 | "$(inherited)", 525 | "@executable_path/Frameworks", 526 | "@loader_path/Frameworks", 527 | ); 528 | PRODUCT_BUNDLE_IDENTIFIER = com.oguzparlak.CoreTests; 529 | PRODUCT_NAME = "$(TARGET_NAME)"; 530 | SWIFT_VERSION = 5.0; 531 | TARGETED_DEVICE_FAMILY = "1,2"; 532 | }; 533 | name = Release; 534 | }; 535 | /* End XCBuildConfiguration section */ 536 | 537 | /* Begin XCConfigurationList section */ 538 | BF5EC46022C52A080068A24C /* Build configuration list for PBXProject "Core" */ = { 539 | isa = XCConfigurationList; 540 | buildConfigurations = ( 541 | BF5EC47822C52A080068A24C /* Debug */, 542 | BF5EC47922C52A080068A24C /* Release */, 543 | ); 544 | defaultConfigurationIsVisible = 0; 545 | defaultConfigurationName = Release; 546 | }; 547 | BF5EC47A22C52A080068A24C /* Build configuration list for PBXNativeTarget "Core" */ = { 548 | isa = XCConfigurationList; 549 | buildConfigurations = ( 550 | BF5EC47B22C52A080068A24C /* Debug */, 551 | BF5EC47C22C52A080068A24C /* Release */, 552 | ); 553 | defaultConfigurationIsVisible = 0; 554 | defaultConfigurationName = Release; 555 | }; 556 | BF5EC47D22C52A080068A24C /* Build configuration list for PBXNativeTarget "CoreTests" */ = { 557 | isa = XCConfigurationList; 558 | buildConfigurations = ( 559 | BF5EC47E22C52A080068A24C /* Debug */, 560 | BF5EC47F22C52A080068A24C /* Release */, 561 | ); 562 | defaultConfigurationIsVisible = 0; 563 | defaultConfigurationName = Release; 564 | }; 565 | /* End XCConfigurationList section */ 566 | }; 567 | rootObject = BF5EC45D22C52A080068A24C /* Project object */; 568 | } 569 | -------------------------------------------------------------------------------- /Core/Core.xcodeproj/xcuserdata/oguzparlak.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Core.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 4 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Core/Core/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/Core/Core/.DS_Store -------------------------------------------------------------------------------- /Core/Core/Coordinator/ConcreteCoordinator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConcreteCoordinator.swift 3 | // Core 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class ConcreteCoordinator: NSObject, Coordinator, UINavigationControllerDelegate { 13 | 14 | // MARK: - Variables 15 | public var navigationController: UINavigationController 16 | 17 | public var childCoordinators = [Coordinator]() 18 | 19 | public init(navigationController: UINavigationController) { 20 | self.navigationController = navigationController 21 | } 22 | 23 | // MARK: - Functions 24 | 25 | /// This method will only be called internally 26 | public func childDidFinish(_ child: Coordinator?) { 27 | for (index, coordinator) in childCoordinators.enumerated() { 28 | if coordinator === child { 29 | childCoordinators.remove(at: index) 30 | break 31 | } 32 | } 33 | } 34 | 35 | public func childCoordinatorShouldNotBeDeleted(navigationController: UINavigationController) -> Bool { 36 | guard let fromViewController = navigationController.getFromViewController() else { 37 | return true 38 | } 39 | if navigationController.viewControllers.contains(fromViewController) { 40 | return true 41 | } 42 | return false 43 | } 44 | 45 | open func start() { 46 | fatalError("start() should be overriden") 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /Core/Core/Coordinator/Coordinator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Coordinator.swift 3 | // Core 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public protocol Coordinator: class { 13 | var childCoordinators: [Coordinator] { get set } 14 | var navigationController: UINavigationController { get set } 15 | 16 | func start() 17 | } 18 | -------------------------------------------------------------------------------- /Core/Core/Coordinator/Storyboarded.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Storyboarded.swift 3 | // Core 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public protocol Storyboarded { } 13 | 14 | extension Storyboarded where Self: UIViewController { 15 | 16 | public static func instantiate() -> Self { 17 | let id = String(describing: self) 18 | let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main) 19 | return storyboard.instantiateViewController(withIdentifier: id) as! Self 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Core/Core/Core.h: -------------------------------------------------------------------------------- 1 | // 2 | // Core.h 3 | // Core 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Core. 12 | FOUNDATION_EXPORT double CoreVersionNumber; 13 | 14 | //! Project version string for Core. 15 | FOUNDATION_EXPORT const unsigned char CoreVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Core/Core/Data/DataManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataManager.swift 3 | // Core 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol DataManager { 12 | 13 | associatedtype T 14 | 15 | func save(with key: String, data: T?) 16 | 17 | func load(with key: String) -> T? 18 | 19 | } 20 | -------------------------------------------------------------------------------- /Core/Core/Data/DataNotifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataNotifier.swift 3 | // Core 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct DataNotifier: DataObserver { 12 | 13 | public typealias T = Data 14 | 15 | private let dataCallback: (Data?) -> () 16 | 17 | private let errorCallback: (Error) -> () 18 | 19 | public init(dataCallback: @escaping (Data?) -> (), errorCallback: @escaping (Error) -> ()) { 20 | self.dataCallback = dataCallback 21 | self.errorCallback = errorCallback 22 | } 23 | 24 | public func onDataChanged(data: Data?) { 25 | dataCallback(data) 26 | } 27 | 28 | public func onError(error: Error) { 29 | errorCallback(error) 30 | } 31 | 32 | } 33 | 34 | public protocol DataObserver { 35 | 36 | associatedtype T 37 | 38 | func onDataChanged(data: T?) 39 | 40 | func onError(error: Error) 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Core/Core/Data/KeyValueManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KeyValueManager.swift 3 | // Core 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class KeyValueManager: DataManager { 12 | 13 | // MARK: - Private Variables 14 | private let dataNotifier: DataNotifier? 15 | 16 | // MARK: - Public Variables 17 | let userDefaults = UserDefaults.standard 18 | 19 | // MARK: - Init 20 | public init(dataNotifier: DataNotifier?) { 21 | self.dataNotifier = dataNotifier 22 | } 23 | 24 | // MARK: - Functions 25 | public func save(with key: String, data: T?) { 26 | let encoder = JSONEncoder() 27 | if let encoded = try? encoder.encode(data) { 28 | userDefaults.set(encoded, forKey: key) 29 | } 30 | } 31 | 32 | public func load(with key: String) -> T? { 33 | if let savedData = userDefaults.object(forKey: key) as? Data { 34 | let decoder = JSONDecoder() 35 | if let codableData = try? decoder.decode(T.self, from: savedData) { 36 | return codableData 37 | } 38 | } 39 | return nil 40 | } 41 | 42 | public func loadCodableList(with key: String) -> [T]? { 43 | if let list = userDefaults.object(forKey: key) as? Data { 44 | let decoder = PropertyListDecoder() 45 | if let codableList = try? decoder.decode([T]?.self, from: list) { 46 | return codableList 47 | } 48 | } 49 | return nil 50 | } 51 | 52 | public func updateCodableList(with key: String, data: [T]?) { 53 | let encoder = PropertyListEncoder() 54 | if let encoded = try? encoder.encode(data) { 55 | userDefaults.set(encoded, forKey: key) 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /Core/Core/Extensions/UI/UIDevice+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIDevice+.swift 3 | // Core 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UIDevice { 12 | public var hasNotch: Bool { 13 | if #available(iOS 11.0, *) { 14 | return UIApplication.shared.delegate?.window??.safeAreaInsets.top ?? 0 > 20 15 | } else { 16 | return false 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Core/Core/Extensions/UI/UINavigationController+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UINavigationController+.swift 3 | // Core 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension UINavigationController { 13 | 14 | public func getFromViewController() -> UIViewController? { 15 | return self.transitionCoordinator?.viewController(forKey: .from) 16 | } 17 | 18 | public func configureTheme() { 19 | self.navigationBar.tintColor = .white 20 | if #available(iOS 11.0, *) { 21 | self.navigationBar.barTintColor = .black 22 | } 23 | navigationBar.barStyle = .black 24 | self.navigationBar.titleTextAttributes = [ 25 | NSAttributedString.Key.font: UIFont(name: "Futura-Bold", size: 17) as Any, 26 | NSAttributedString.Key.foregroundColor: UIColor.white 27 | ] 28 | if #available(iOS 11.0, *) { 29 | self.navigationBar.largeTitleTextAttributes = [ 30 | NSAttributedString.Key.font: UIFont(name: "Futura-Bold", size: 34) as Any, 31 | NSAttributedString.Key.foregroundColor: UIColor.white 32 | ] 33 | } else { 34 | // Fallback on earlier versions 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Core/Core/Extensions/UI/UIView+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+.swift 3 | // Core 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension UIView { 13 | 14 | public func applyGradient(firstColor: UIColor, secondColor: UIColor) { 15 | let gradient = CAGradientLayer() 16 | 17 | // TODO Change gradient position 18 | // gradient.startPoint = CGPoint(x: 0, y: 0) 19 | // gradient.endPoint = CGPoint(x: 0, y: 0) 20 | gradient.frame = self.bounds 21 | gradient.colors = [firstColor.cgColor, secondColor.cgColor] 22 | 23 | self.layer.insertSublayer(gradient, at: 0) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Core/Core/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /Core/Core/Repository/Repository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Repository.swift 3 | // Core 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Networking 11 | 12 | public protocol Repository { 13 | 14 | associatedtype T 15 | 16 | func getLocalDataSource() -> T 17 | 18 | func getRemoteDataSource(responseCallback: @escaping (Result) -> Void) 19 | } 20 | -------------------------------------------------------------------------------- /Core/Core/UI/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/Core/Core/UI/.DS_Store -------------------------------------------------------------------------------- /Core/CoreTests/CoreTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CoreTests.swift 3 | // CoreTests 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Core 11 | 12 | class CoreTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Core/CoreTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BF014FE322CE7D42006669CD /* TVShowListingView+UITableViewDataSourcePrefetching.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF014FE222CE7D42006669CD /* TVShowListingView+UITableViewDataSourcePrefetching.swift */; }; 11 | BF014FE522CE819C006669CD /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF014FE422CE819C006669CD /* Core.framework */; }; 12 | BF014FE622CE819C006669CD /* Core.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF014FE422CE819C006669CD /* Core.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 13 | BF014FE822CE819C006669CD /* Networking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF014FE722CE819C006669CD /* Networking.framework */; }; 14 | BF014FE922CE819C006669CD /* Networking.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF014FE722CE819C006669CD /* Networking.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 15 | BF0BA6C122C8C4E400AA3CA3 /* TVShowEndPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0BA6C022C8C4E400AA3CA3 /* TVShowEndPoint.swift */; }; 16 | BF0BA6C622C8C7EB00AA3CA3 /* TVShowRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0BA6C522C8C7EB00AA3CA3 /* TVShowRepository.swift */; }; 17 | BF0BA6C922C8CB6B00AA3CA3 /* TVShowDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0BA6C822C8CB6B00AA3CA3 /* TVShowDataManager.swift */; }; 18 | BF0BA6CE22C8CBE700AA3CA3 /* TVShow.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0BA6CD22C8CBE700AA3CA3 /* TVShow.swift */; }; 19 | BF0BA6D022C8CDBD00AA3CA3 /* TVShowContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0BA6CF22C8CDBD00AA3CA3 /* TVShowContainer.swift */; }; 20 | BF0BA6D322C8D61400AA3CA3 /* TVShowListingCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0BA6D222C8D61400AA3CA3 /* TVShowListingCoordinator.swift */; }; 21 | BF0BA6D622C8DEBA00AA3CA3 /* RootController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0BA6D522C8DEBA00AA3CA3 /* RootController.swift */; }; 22 | BF0BA6D822C8DFC200AA3CA3 /* TVShowViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0BA6D722C8DFC200AA3CA3 /* TVShowViewModel.swift */; }; 23 | BF0BA6DB22C8E06000AA3CA3 /* TVShowInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0BA6DA22C8E06000AA3CA3 /* TVShowInteractor.swift */; }; 24 | BF5EC3D722C527940068A24C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC3D622C527940068A24C /* AppDelegate.swift */; }; 25 | BF5EC3D922C527940068A24C /* TVShowListingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC3D822C527940068A24C /* TVShowListingView.swift */; }; 26 | BF5EC3DC22C527940068A24C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF5EC3DA22C527940068A24C /* Main.storyboard */; }; 27 | BF5EC3DE22C527940068A24C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF5EC3DD22C527940068A24C /* Assets.xcassets */; }; 28 | BF5EC3E122C527940068A24C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF5EC3DF22C527940068A24C /* LaunchScreen.storyboard */; }; 29 | BFF3459122C91F8500D7470C /* TVShowListingView+TVShowInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF3459022C91F8500D7470C /* TVShowListingView+TVShowInteractor.swift */; }; 30 | BFF3459422C91FC000D7470C /* TVShowListView+UITableViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF3459322C91FC000D7470C /* TVShowListView+UITableViewDelegate.swift */; }; 31 | BFF3459622C91FEB00D7470C /* TVShowListingView+UITableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF3459522C91FEB00D7470C /* TVShowListingView+UITableViewDataSource.swift */; }; 32 | BFF3459922C92E8700D7470C /* MovieListingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF3459722C92E8700D7470C /* MovieListingCell.swift */; }; 33 | BFF3459A22C92E8700D7470C /* MovieListingCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFF3459822C92E8700D7470C /* MovieListingCell.xib */; }; 34 | BFF3459C22C9302900D7470C /* TVShowCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF3459B22C9302900D7470C /* TVShowCellViewModel.swift */; }; 35 | D8DDA29F35638ACE71246EF1 /* Pods_MVVM_C_App_Core_Networking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDE3D49166EE0FB3886B9E36 /* Pods_MVVM_C_App_Core_Networking.framework */; }; 36 | /* End PBXBuildFile section */ 37 | 38 | /* Begin PBXContainerItemProxy section */ 39 | BF5EC3E822C527940068A24C /* PBXContainerItemProxy */ = { 40 | isa = PBXContainerItemProxy; 41 | containerPortal = BF5EC3CB22C527940068A24C /* Project object */; 42 | proxyType = 1; 43 | remoteGlobalIDString = BF5EC3D222C527940068A24C; 44 | remoteInfo = "MVVM-C-App-Core-Networking"; 45 | }; 46 | BF5EC3F322C527940068A24C /* PBXContainerItemProxy */ = { 47 | isa = PBXContainerItemProxy; 48 | containerPortal = BF5EC3CB22C527940068A24C /* Project object */; 49 | proxyType = 1; 50 | remoteGlobalIDString = BF5EC3D222C527940068A24C; 51 | remoteInfo = "MVVM-C-App-Core-Networking"; 52 | }; 53 | /* End PBXContainerItemProxy section */ 54 | 55 | /* Begin PBXCopyFilesBuildPhase section */ 56 | BF17C62722C8FFF80064402F /* Embed Frameworks */ = { 57 | isa = PBXCopyFilesBuildPhase; 58 | buildActionMask = 2147483647; 59 | dstPath = ""; 60 | dstSubfolderSpec = 10; 61 | files = ( 62 | BF014FE922CE819C006669CD /* Networking.framework in Embed Frameworks */, 63 | BF014FE622CE819C006669CD /* Core.framework in Embed Frameworks */, 64 | ); 65 | name = "Embed Frameworks"; 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXCopyFilesBuildPhase section */ 69 | 70 | /* Begin PBXFileReference section */ 71 | 95D431D1880253199DA0EF7A /* Pods-MVVM-C-App-Core-Networking.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MVVM-C-App-Core-Networking.debug.xcconfig"; path = "Target Support Files/Pods-MVVM-C-App-Core-Networking/Pods-MVVM-C-App-Core-Networking.debug.xcconfig"; sourceTree = ""; }; 72 | AA20893E4835DF8CF8ECA271 /* Pods-MVVM-C-App-Core-Networking.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MVVM-C-App-Core-Networking.release.xcconfig"; path = "Target Support Files/Pods-MVVM-C-App-Core-Networking/Pods-MVVM-C-App-Core-Networking.release.xcconfig"; sourceTree = ""; }; 73 | BF014FE222CE7D42006669CD /* TVShowListingView+UITableViewDataSourcePrefetching.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TVShowListingView+UITableViewDataSourcePrefetching.swift"; sourceTree = ""; }; 74 | BF014FE422CE819C006669CD /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | BF014FE722CE819C006669CD /* Networking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Networking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 76 | BF0BA6C022C8C4E400AA3CA3 /* TVShowEndPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVShowEndPoint.swift; sourceTree = ""; }; 77 | BF0BA6C522C8C7EB00AA3CA3 /* TVShowRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVShowRepository.swift; sourceTree = ""; }; 78 | BF0BA6C822C8CB6B00AA3CA3 /* TVShowDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVShowDataManager.swift; sourceTree = ""; }; 79 | BF0BA6CD22C8CBE700AA3CA3 /* TVShow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVShow.swift; sourceTree = ""; }; 80 | BF0BA6CF22C8CDBD00AA3CA3 /* TVShowContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVShowContainer.swift; sourceTree = ""; }; 81 | BF0BA6D222C8D61400AA3CA3 /* TVShowListingCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVShowListingCoordinator.swift; sourceTree = ""; }; 82 | BF0BA6D522C8DEBA00AA3CA3 /* RootController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootController.swift; sourceTree = ""; }; 83 | BF0BA6D722C8DFC200AA3CA3 /* TVShowViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVShowViewModel.swift; sourceTree = ""; }; 84 | BF0BA6DA22C8E06000AA3CA3 /* TVShowInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVShowInteractor.swift; sourceTree = ""; }; 85 | BF5EC3D322C527940068A24C /* MVVM-C-App-Core-Networking.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MVVM-C-App-Core-Networking.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 86 | BF5EC3D622C527940068A24C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 87 | BF5EC3D822C527940068A24C /* TVShowListingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVShowListingView.swift; sourceTree = ""; }; 88 | BF5EC3DB22C527940068A24C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 89 | BF5EC3DD22C527940068A24C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 90 | BF5EC3E022C527940068A24C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 91 | BF5EC3E222C527940068A24C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 92 | BF5EC3E722C527940068A24C /* MVVM-C-App-Core-NetworkingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "MVVM-C-App-Core-NetworkingTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 93 | BF5EC3F222C527940068A24C /* MVVM-C-App-Core-NetworkingUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "MVVM-C-App-Core-NetworkingUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 94 | BFF3459022C91F8500D7470C /* TVShowListingView+TVShowInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TVShowListingView+TVShowInteractor.swift"; sourceTree = ""; }; 95 | BFF3459322C91FC000D7470C /* TVShowListView+UITableViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TVShowListView+UITableViewDelegate.swift"; sourceTree = ""; }; 96 | BFF3459522C91FEB00D7470C /* TVShowListingView+UITableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TVShowListingView+UITableViewDataSource.swift"; sourceTree = ""; }; 97 | BFF3459722C92E8700D7470C /* MovieListingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieListingCell.swift; sourceTree = ""; }; 98 | BFF3459822C92E8700D7470C /* MovieListingCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MovieListingCell.xib; sourceTree = ""; }; 99 | BFF3459B22C9302900D7470C /* TVShowCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVShowCellViewModel.swift; sourceTree = ""; }; 100 | DDE3D49166EE0FB3886B9E36 /* Pods_MVVM_C_App_Core_Networking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MVVM_C_App_Core_Networking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 101 | /* End PBXFileReference section */ 102 | 103 | /* Begin PBXFrameworksBuildPhase section */ 104 | BF5EC3D022C527940068A24C /* Frameworks */ = { 105 | isa = PBXFrameworksBuildPhase; 106 | buildActionMask = 2147483647; 107 | files = ( 108 | BF014FE822CE819C006669CD /* Networking.framework in Frameworks */, 109 | BF014FE522CE819C006669CD /* Core.framework in Frameworks */, 110 | D8DDA29F35638ACE71246EF1 /* Pods_MVVM_C_App_Core_Networking.framework in Frameworks */, 111 | ); 112 | runOnlyForDeploymentPostprocessing = 0; 113 | }; 114 | BF5EC3E422C527940068A24C /* Frameworks */ = { 115 | isa = PBXFrameworksBuildPhase; 116 | buildActionMask = 2147483647; 117 | files = ( 118 | ); 119 | runOnlyForDeploymentPostprocessing = 0; 120 | }; 121 | BF5EC3EF22C527940068A24C /* Frameworks */ = { 122 | isa = PBXFrameworksBuildPhase; 123 | buildActionMask = 2147483647; 124 | files = ( 125 | ); 126 | runOnlyForDeploymentPostprocessing = 0; 127 | }; 128 | /* End PBXFrameworksBuildPhase section */ 129 | 130 | /* Begin PBXGroup section */ 131 | 6E7AF7E20FDCEFD9FE9D47DA /* Pods */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 95D431D1880253199DA0EF7A /* Pods-MVVM-C-App-Core-Networking.debug.xcconfig */, 135 | AA20893E4835DF8CF8ECA271 /* Pods-MVVM-C-App-Core-Networking.release.xcconfig */, 136 | ); 137 | name = Pods; 138 | path = Pods; 139 | sourceTree = ""; 140 | }; 141 | BF0BA6BF22C8C4D400AA3CA3 /* Networking */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | BF0BA6C022C8C4E400AA3CA3 /* TVShowEndPoint.swift */, 145 | ); 146 | path = Networking; 147 | sourceTree = ""; 148 | }; 149 | BF0BA6C422C8C7DC00AA3CA3 /* Repository */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | BF0BA6C522C8C7EB00AA3CA3 /* TVShowRepository.swift */, 153 | ); 154 | path = Repository; 155 | sourceTree = ""; 156 | }; 157 | BF0BA6C722C8CB4F00AA3CA3 /* Data */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | BF0BA6C822C8CB6B00AA3CA3 /* TVShowDataManager.swift */, 161 | ); 162 | path = Data; 163 | sourceTree = ""; 164 | }; 165 | BF0BA6CA22C8CBCA00AA3CA3 /* Model */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | BF0BA6CD22C8CBE700AA3CA3 /* TVShow.swift */, 169 | BF0BA6CF22C8CDBD00AA3CA3 /* TVShowContainer.swift */, 170 | ); 171 | path = Model; 172 | sourceTree = ""; 173 | }; 174 | BF0BA6CB22C8CBD000AA3CA3 /* View */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | BF5EC3D822C527940068A24C /* TVShowListingView.swift */, 178 | BFF3459722C92E8700D7470C /* MovieListingCell.swift */, 179 | BFF3459822C92E8700D7470C /* MovieListingCell.xib */, 180 | ); 181 | path = View; 182 | sourceTree = ""; 183 | }; 184 | BF0BA6CC22C8CBD400AA3CA3 /* ViewModel */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | BF0BA6D722C8DFC200AA3CA3 /* TVShowViewModel.swift */, 188 | BFF3459B22C9302900D7470C /* TVShowCellViewModel.swift */, 189 | ); 190 | path = ViewModel; 191 | sourceTree = ""; 192 | }; 193 | BF0BA6D122C8D5F100AA3CA3 /* Coordinator */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | BF0BA6D222C8D61400AA3CA3 /* TVShowListingCoordinator.swift */, 197 | ); 198 | path = Coordinator; 199 | sourceTree = ""; 200 | }; 201 | BF0BA6D422C8DEA600AA3CA3 /* Root */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | BF0BA6D522C8DEBA00AA3CA3 /* RootController.swift */, 205 | ); 206 | path = Root; 207 | sourceTree = ""; 208 | }; 209 | BF0BA6D922C8E04300AA3CA3 /* Interactor */ = { 210 | isa = PBXGroup; 211 | children = ( 212 | BF0BA6DA22C8E06000AA3CA3 /* TVShowInteractor.swift */, 213 | ); 214 | path = Interactor; 215 | sourceTree = ""; 216 | }; 217 | BF5EC3CA22C527940068A24C = { 218 | isa = PBXGroup; 219 | children = ( 220 | BF014FE722CE819C006669CD /* Networking.framework */, 221 | BF014FE422CE819C006669CD /* Core.framework */, 222 | BF5EC3D622C527940068A24C /* AppDelegate.swift */, 223 | BF0BA6D422C8DEA600AA3CA3 /* Root */, 224 | BF5EC48522C52A690068A24C /* Frameworks */, 225 | BF5EC3D522C527940068A24C /* MVVM-C-App-Core-Networking */, 226 | BF5EC3D422C527940068A24C /* Products */, 227 | 6E7AF7E20FDCEFD9FE9D47DA /* Pods */, 228 | ); 229 | sourceTree = ""; 230 | }; 231 | BF5EC3D422C527940068A24C /* Products */ = { 232 | isa = PBXGroup; 233 | children = ( 234 | BF5EC3D322C527940068A24C /* MVVM-C-App-Core-Networking.app */, 235 | BF5EC3E722C527940068A24C /* MVVM-C-App-Core-NetworkingTests.xctest */, 236 | BF5EC3F222C527940068A24C /* MVVM-C-App-Core-NetworkingUITests.xctest */, 237 | ); 238 | name = Products; 239 | sourceTree = ""; 240 | }; 241 | BF5EC3D522C527940068A24C /* MVVM-C-App-Core-Networking */ = { 242 | isa = PBXGroup; 243 | children = ( 244 | BFF3458F22C91F7000D7470C /* Extension */, 245 | BF0BA6D922C8E04300AA3CA3 /* Interactor */, 246 | BF0BA6D122C8D5F100AA3CA3 /* Coordinator */, 247 | BF0BA6CA22C8CBCA00AA3CA3 /* Model */, 248 | BF0BA6CB22C8CBD000AA3CA3 /* View */, 249 | BF0BA6CC22C8CBD400AA3CA3 /* ViewModel */, 250 | BF0BA6C722C8CB4F00AA3CA3 /* Data */, 251 | BF0BA6C422C8C7DC00AA3CA3 /* Repository */, 252 | BF0BA6BF22C8C4D400AA3CA3 /* Networking */, 253 | BF5EC3DA22C527940068A24C /* Main.storyboard */, 254 | BF5EC3DD22C527940068A24C /* Assets.xcassets */, 255 | BF5EC3DF22C527940068A24C /* LaunchScreen.storyboard */, 256 | BF5EC3E222C527940068A24C /* Info.plist */, 257 | ); 258 | path = "MVVM-C-App-Core-Networking"; 259 | sourceTree = ""; 260 | }; 261 | BF5EC48522C52A690068A24C /* Frameworks */ = { 262 | isa = PBXGroup; 263 | children = ( 264 | DDE3D49166EE0FB3886B9E36 /* Pods_MVVM_C_App_Core_Networking.framework */, 265 | ); 266 | path = Frameworks; 267 | sourceTree = ""; 268 | }; 269 | BFF3458F22C91F7000D7470C /* Extension */ = { 270 | isa = PBXGroup; 271 | children = ( 272 | BFF3459022C91F8500D7470C /* TVShowListingView+TVShowInteractor.swift */, 273 | BFF3459322C91FC000D7470C /* TVShowListView+UITableViewDelegate.swift */, 274 | BFF3459522C91FEB00D7470C /* TVShowListingView+UITableViewDataSource.swift */, 275 | BF014FE222CE7D42006669CD /* TVShowListingView+UITableViewDataSourcePrefetching.swift */, 276 | ); 277 | path = Extension; 278 | sourceTree = ""; 279 | }; 280 | /* End PBXGroup section */ 281 | 282 | /* Begin PBXNativeTarget section */ 283 | BF5EC3D222C527940068A24C /* MVVM-C-App-Core-Networking */ = { 284 | isa = PBXNativeTarget; 285 | buildConfigurationList = BF5EC3FB22C527940068A24C /* Build configuration list for PBXNativeTarget "MVVM-C-App-Core-Networking" */; 286 | buildPhases = ( 287 | 6D97E8B53F8C050DD12C6F4B /* [CP] Check Pods Manifest.lock */, 288 | BF5EC3CF22C527940068A24C /* Sources */, 289 | BF5EC3D022C527940068A24C /* Frameworks */, 290 | BF5EC3D122C527940068A24C /* Resources */, 291 | BF17C62722C8FFF80064402F /* Embed Frameworks */, 292 | 0C4B413B395C6B2BFC6F61E3 /* [CP] Embed Pods Frameworks */, 293 | ); 294 | buildRules = ( 295 | ); 296 | dependencies = ( 297 | ); 298 | name = "MVVM-C-App-Core-Networking"; 299 | productName = "MVVM-C-App-Core-Networking"; 300 | productReference = BF5EC3D322C527940068A24C /* MVVM-C-App-Core-Networking.app */; 301 | productType = "com.apple.product-type.application"; 302 | }; 303 | BF5EC3E622C527940068A24C /* MVVM-C-App-Core-NetworkingTests */ = { 304 | isa = PBXNativeTarget; 305 | buildConfigurationList = BF5EC3FE22C527940068A24C /* Build configuration list for PBXNativeTarget "MVVM-C-App-Core-NetworkingTests" */; 306 | buildPhases = ( 307 | BF5EC3E322C527940068A24C /* Sources */, 308 | BF5EC3E422C527940068A24C /* Frameworks */, 309 | BF5EC3E522C527940068A24C /* Resources */, 310 | ); 311 | buildRules = ( 312 | ); 313 | dependencies = ( 314 | BF5EC3E922C527940068A24C /* PBXTargetDependency */, 315 | ); 316 | name = "MVVM-C-App-Core-NetworkingTests"; 317 | productName = "MVVM-C-App-Core-NetworkingTests"; 318 | productReference = BF5EC3E722C527940068A24C /* MVVM-C-App-Core-NetworkingTests.xctest */; 319 | productType = "com.apple.product-type.bundle.unit-test"; 320 | }; 321 | BF5EC3F122C527940068A24C /* MVVM-C-App-Core-NetworkingUITests */ = { 322 | isa = PBXNativeTarget; 323 | buildConfigurationList = BF5EC40122C527940068A24C /* Build configuration list for PBXNativeTarget "MVVM-C-App-Core-NetworkingUITests" */; 324 | buildPhases = ( 325 | BF5EC3EE22C527940068A24C /* Sources */, 326 | BF5EC3EF22C527940068A24C /* Frameworks */, 327 | BF5EC3F022C527940068A24C /* Resources */, 328 | ); 329 | buildRules = ( 330 | ); 331 | dependencies = ( 332 | BF5EC3F422C527940068A24C /* PBXTargetDependency */, 333 | ); 334 | name = "MVVM-C-App-Core-NetworkingUITests"; 335 | productName = "MVVM-C-App-Core-NetworkingUITests"; 336 | productReference = BF5EC3F222C527940068A24C /* MVVM-C-App-Core-NetworkingUITests.xctest */; 337 | productType = "com.apple.product-type.bundle.ui-testing"; 338 | }; 339 | /* End PBXNativeTarget section */ 340 | 341 | /* Begin PBXProject section */ 342 | BF5EC3CB22C527940068A24C /* Project object */ = { 343 | isa = PBXProject; 344 | attributes = { 345 | LastSwiftUpdateCheck = 1020; 346 | LastUpgradeCheck = 1020; 347 | ORGANIZATIONNAME = "Oguz Parlak"; 348 | TargetAttributes = { 349 | BF5EC3D222C527940068A24C = { 350 | CreatedOnToolsVersion = 10.2.1; 351 | }; 352 | BF5EC3E622C527940068A24C = { 353 | CreatedOnToolsVersion = 10.2.1; 354 | TestTargetID = BF5EC3D222C527940068A24C; 355 | }; 356 | BF5EC3F122C527940068A24C = { 357 | CreatedOnToolsVersion = 10.2.1; 358 | TestTargetID = BF5EC3D222C527940068A24C; 359 | }; 360 | }; 361 | }; 362 | buildConfigurationList = BF5EC3CE22C527940068A24C /* Build configuration list for PBXProject "MVVM-C-App-Core-Networking" */; 363 | compatibilityVersion = "Xcode 9.3"; 364 | developmentRegion = en; 365 | hasScannedForEncodings = 0; 366 | knownRegions = ( 367 | en, 368 | Base, 369 | ); 370 | mainGroup = BF5EC3CA22C527940068A24C; 371 | productRefGroup = BF5EC3D422C527940068A24C /* Products */; 372 | projectDirPath = ""; 373 | projectRoot = ""; 374 | targets = ( 375 | BF5EC3D222C527940068A24C /* MVVM-C-App-Core-Networking */, 376 | BF5EC3E622C527940068A24C /* MVVM-C-App-Core-NetworkingTests */, 377 | BF5EC3F122C527940068A24C /* MVVM-C-App-Core-NetworkingUITests */, 378 | ); 379 | }; 380 | /* End PBXProject section */ 381 | 382 | /* Begin PBXResourcesBuildPhase section */ 383 | BF5EC3D122C527940068A24C /* Resources */ = { 384 | isa = PBXResourcesBuildPhase; 385 | buildActionMask = 2147483647; 386 | files = ( 387 | BF5EC3E122C527940068A24C /* LaunchScreen.storyboard in Resources */, 388 | BF5EC3DE22C527940068A24C /* Assets.xcassets in Resources */, 389 | BF5EC3DC22C527940068A24C /* Main.storyboard in Resources */, 390 | BFF3459A22C92E8700D7470C /* MovieListingCell.xib in Resources */, 391 | ); 392 | runOnlyForDeploymentPostprocessing = 0; 393 | }; 394 | BF5EC3E522C527940068A24C /* Resources */ = { 395 | isa = PBXResourcesBuildPhase; 396 | buildActionMask = 2147483647; 397 | files = ( 398 | ); 399 | runOnlyForDeploymentPostprocessing = 0; 400 | }; 401 | BF5EC3F022C527940068A24C /* Resources */ = { 402 | isa = PBXResourcesBuildPhase; 403 | buildActionMask = 2147483647; 404 | files = ( 405 | ); 406 | runOnlyForDeploymentPostprocessing = 0; 407 | }; 408 | /* End PBXResourcesBuildPhase section */ 409 | 410 | /* Begin PBXShellScriptBuildPhase section */ 411 | 0C4B413B395C6B2BFC6F61E3 /* [CP] Embed Pods Frameworks */ = { 412 | isa = PBXShellScriptBuildPhase; 413 | buildActionMask = 2147483647; 414 | files = ( 415 | ); 416 | inputFileListPaths = ( 417 | "${PODS_ROOT}/Target Support Files/Pods-MVVM-C-App-Core-Networking/Pods-MVVM-C-App-Core-Networking-frameworks-${CONFIGURATION}-input-files.xcfilelist", 418 | ); 419 | name = "[CP] Embed Pods Frameworks"; 420 | outputFileListPaths = ( 421 | "${PODS_ROOT}/Target Support Files/Pods-MVVM-C-App-Core-Networking/Pods-MVVM-C-App-Core-Networking-frameworks-${CONFIGURATION}-output-files.xcfilelist", 422 | ); 423 | runOnlyForDeploymentPostprocessing = 0; 424 | shellPath = /bin/sh; 425 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MVVM-C-App-Core-Networking/Pods-MVVM-C-App-Core-Networking-frameworks.sh\"\n"; 426 | showEnvVarsInLog = 0; 427 | }; 428 | 6D97E8B53F8C050DD12C6F4B /* [CP] Check Pods Manifest.lock */ = { 429 | isa = PBXShellScriptBuildPhase; 430 | buildActionMask = 2147483647; 431 | files = ( 432 | ); 433 | inputFileListPaths = ( 434 | ); 435 | inputPaths = ( 436 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 437 | "${PODS_ROOT}/Manifest.lock", 438 | ); 439 | name = "[CP] Check Pods Manifest.lock"; 440 | outputFileListPaths = ( 441 | ); 442 | outputPaths = ( 443 | "$(DERIVED_FILE_DIR)/Pods-MVVM-C-App-Core-Networking-checkManifestLockResult.txt", 444 | ); 445 | runOnlyForDeploymentPostprocessing = 0; 446 | shellPath = /bin/sh; 447 | 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"; 448 | showEnvVarsInLog = 0; 449 | }; 450 | /* End PBXShellScriptBuildPhase section */ 451 | 452 | /* Begin PBXSourcesBuildPhase section */ 453 | BF5EC3CF22C527940068A24C /* Sources */ = { 454 | isa = PBXSourcesBuildPhase; 455 | buildActionMask = 2147483647; 456 | files = ( 457 | BF0BA6C622C8C7EB00AA3CA3 /* TVShowRepository.swift in Sources */, 458 | BF0BA6D022C8CDBD00AA3CA3 /* TVShowContainer.swift in Sources */, 459 | BF0BA6D322C8D61400AA3CA3 /* TVShowListingCoordinator.swift in Sources */, 460 | BF014FE322CE7D42006669CD /* TVShowListingView+UITableViewDataSourcePrefetching.swift in Sources */, 461 | BF0BA6C922C8CB6B00AA3CA3 /* TVShowDataManager.swift in Sources */, 462 | BF0BA6CE22C8CBE700AA3CA3 /* TVShow.swift in Sources */, 463 | BFF3459622C91FEB00D7470C /* TVShowListingView+UITableViewDataSource.swift in Sources */, 464 | BFF3459122C91F8500D7470C /* TVShowListingView+TVShowInteractor.swift in Sources */, 465 | BF0BA6D622C8DEBA00AA3CA3 /* RootController.swift in Sources */, 466 | BF5EC3D922C527940068A24C /* TVShowListingView.swift in Sources */, 467 | BF5EC3D722C527940068A24C /* AppDelegate.swift in Sources */, 468 | BF0BA6C122C8C4E400AA3CA3 /* TVShowEndPoint.swift in Sources */, 469 | BFF3459C22C9302900D7470C /* TVShowCellViewModel.swift in Sources */, 470 | BF0BA6D822C8DFC200AA3CA3 /* TVShowViewModel.swift in Sources */, 471 | BFF3459922C92E8700D7470C /* MovieListingCell.swift in Sources */, 472 | BFF3459422C91FC000D7470C /* TVShowListView+UITableViewDelegate.swift in Sources */, 473 | BF0BA6DB22C8E06000AA3CA3 /* TVShowInteractor.swift in Sources */, 474 | ); 475 | runOnlyForDeploymentPostprocessing = 0; 476 | }; 477 | BF5EC3E322C527940068A24C /* Sources */ = { 478 | isa = PBXSourcesBuildPhase; 479 | buildActionMask = 2147483647; 480 | files = ( 481 | ); 482 | runOnlyForDeploymentPostprocessing = 0; 483 | }; 484 | BF5EC3EE22C527940068A24C /* Sources */ = { 485 | isa = PBXSourcesBuildPhase; 486 | buildActionMask = 2147483647; 487 | files = ( 488 | ); 489 | runOnlyForDeploymentPostprocessing = 0; 490 | }; 491 | /* End PBXSourcesBuildPhase section */ 492 | 493 | /* Begin PBXTargetDependency section */ 494 | BF5EC3E922C527940068A24C /* PBXTargetDependency */ = { 495 | isa = PBXTargetDependency; 496 | target = BF5EC3D222C527940068A24C /* MVVM-C-App-Core-Networking */; 497 | targetProxy = BF5EC3E822C527940068A24C /* PBXContainerItemProxy */; 498 | }; 499 | BF5EC3F422C527940068A24C /* PBXTargetDependency */ = { 500 | isa = PBXTargetDependency; 501 | target = BF5EC3D222C527940068A24C /* MVVM-C-App-Core-Networking */; 502 | targetProxy = BF5EC3F322C527940068A24C /* PBXContainerItemProxy */; 503 | }; 504 | /* End PBXTargetDependency section */ 505 | 506 | /* Begin PBXVariantGroup section */ 507 | BF5EC3DA22C527940068A24C /* Main.storyboard */ = { 508 | isa = PBXVariantGroup; 509 | children = ( 510 | BF5EC3DB22C527940068A24C /* Base */, 511 | ); 512 | name = Main.storyboard; 513 | sourceTree = ""; 514 | }; 515 | BF5EC3DF22C527940068A24C /* LaunchScreen.storyboard */ = { 516 | isa = PBXVariantGroup; 517 | children = ( 518 | BF5EC3E022C527940068A24C /* Base */, 519 | ); 520 | name = LaunchScreen.storyboard; 521 | sourceTree = ""; 522 | }; 523 | /* End PBXVariantGroup section */ 524 | 525 | /* Begin XCBuildConfiguration section */ 526 | BF5EC3F922C527940068A24C /* Debug */ = { 527 | isa = XCBuildConfiguration; 528 | buildSettings = { 529 | ALWAYS_SEARCH_USER_PATHS = NO; 530 | CLANG_ANALYZER_NONNULL = YES; 531 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 532 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 533 | CLANG_CXX_LIBRARY = "libc++"; 534 | CLANG_ENABLE_MODULES = YES; 535 | CLANG_ENABLE_OBJC_ARC = YES; 536 | CLANG_ENABLE_OBJC_WEAK = YES; 537 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 538 | CLANG_WARN_BOOL_CONVERSION = YES; 539 | CLANG_WARN_COMMA = YES; 540 | CLANG_WARN_CONSTANT_CONVERSION = YES; 541 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 542 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 543 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 544 | CLANG_WARN_EMPTY_BODY = YES; 545 | CLANG_WARN_ENUM_CONVERSION = YES; 546 | CLANG_WARN_INFINITE_RECURSION = YES; 547 | CLANG_WARN_INT_CONVERSION = YES; 548 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 549 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 550 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 551 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 552 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 553 | CLANG_WARN_STRICT_PROTOTYPES = YES; 554 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 555 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 556 | CLANG_WARN_UNREACHABLE_CODE = YES; 557 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 558 | CODE_SIGN_IDENTITY = "iPhone Developer"; 559 | COPY_PHASE_STRIP = NO; 560 | DEBUG_INFORMATION_FORMAT = dwarf; 561 | ENABLE_STRICT_OBJC_MSGSEND = YES; 562 | ENABLE_TESTABILITY = YES; 563 | GCC_C_LANGUAGE_STANDARD = gnu11; 564 | GCC_DYNAMIC_NO_PIC = NO; 565 | GCC_NO_COMMON_BLOCKS = YES; 566 | GCC_OPTIMIZATION_LEVEL = 0; 567 | GCC_PREPROCESSOR_DEFINITIONS = ( 568 | "DEBUG=1", 569 | "$(inherited)", 570 | ); 571 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 572 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 573 | GCC_WARN_UNDECLARED_SELECTOR = YES; 574 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 575 | GCC_WARN_UNUSED_FUNCTION = YES; 576 | GCC_WARN_UNUSED_VARIABLE = YES; 577 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 578 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 579 | MTL_FAST_MATH = YES; 580 | ONLY_ACTIVE_ARCH = YES; 581 | SDKROOT = iphoneos; 582 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 583 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 584 | }; 585 | name = Debug; 586 | }; 587 | BF5EC3FA22C527940068A24C /* Release */ = { 588 | isa = XCBuildConfiguration; 589 | buildSettings = { 590 | ALWAYS_SEARCH_USER_PATHS = NO; 591 | CLANG_ANALYZER_NONNULL = YES; 592 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 593 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 594 | CLANG_CXX_LIBRARY = "libc++"; 595 | CLANG_ENABLE_MODULES = YES; 596 | CLANG_ENABLE_OBJC_ARC = YES; 597 | CLANG_ENABLE_OBJC_WEAK = YES; 598 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 599 | CLANG_WARN_BOOL_CONVERSION = YES; 600 | CLANG_WARN_COMMA = YES; 601 | CLANG_WARN_CONSTANT_CONVERSION = YES; 602 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 603 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 604 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 605 | CLANG_WARN_EMPTY_BODY = YES; 606 | CLANG_WARN_ENUM_CONVERSION = YES; 607 | CLANG_WARN_INFINITE_RECURSION = YES; 608 | CLANG_WARN_INT_CONVERSION = YES; 609 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 610 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 611 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 612 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 613 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 614 | CLANG_WARN_STRICT_PROTOTYPES = YES; 615 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 616 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 617 | CLANG_WARN_UNREACHABLE_CODE = YES; 618 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 619 | CODE_SIGN_IDENTITY = "iPhone Developer"; 620 | COPY_PHASE_STRIP = NO; 621 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 622 | ENABLE_NS_ASSERTIONS = NO; 623 | ENABLE_STRICT_OBJC_MSGSEND = YES; 624 | GCC_C_LANGUAGE_STANDARD = gnu11; 625 | GCC_NO_COMMON_BLOCKS = YES; 626 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 627 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 628 | GCC_WARN_UNDECLARED_SELECTOR = YES; 629 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 630 | GCC_WARN_UNUSED_FUNCTION = YES; 631 | GCC_WARN_UNUSED_VARIABLE = YES; 632 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 633 | MTL_ENABLE_DEBUG_INFO = NO; 634 | MTL_FAST_MATH = YES; 635 | SDKROOT = iphoneos; 636 | SWIFT_COMPILATION_MODE = wholemodule; 637 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 638 | VALIDATE_PRODUCT = YES; 639 | }; 640 | name = Release; 641 | }; 642 | BF5EC3FC22C527940068A24C /* Debug */ = { 643 | isa = XCBuildConfiguration; 644 | baseConfigurationReference = 95D431D1880253199DA0EF7A /* Pods-MVVM-C-App-Core-Networking.debug.xcconfig */; 645 | buildSettings = { 646 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 647 | CODE_SIGN_STYLE = Automatic; 648 | DEVELOPMENT_TEAM = HL7GD8S24Y; 649 | INFOPLIST_FILE = "MVVM-C-App-Core-Networking/Info.plist"; 650 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 651 | LD_RUNPATH_SEARCH_PATHS = ( 652 | "$(inherited)", 653 | "@executable_path/Frameworks", 654 | ); 655 | PRODUCT_BUNDLE_IDENTIFIER = "com.oguzparlak.MVVM-C-App-Core-Networking"; 656 | PRODUCT_NAME = "$(TARGET_NAME)"; 657 | SWIFT_VERSION = 5.0; 658 | TARGETED_DEVICE_FAMILY = "1,2"; 659 | }; 660 | name = Debug; 661 | }; 662 | BF5EC3FD22C527940068A24C /* Release */ = { 663 | isa = XCBuildConfiguration; 664 | baseConfigurationReference = AA20893E4835DF8CF8ECA271 /* Pods-MVVM-C-App-Core-Networking.release.xcconfig */; 665 | buildSettings = { 666 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 667 | CODE_SIGN_STYLE = Automatic; 668 | DEVELOPMENT_TEAM = HL7GD8S24Y; 669 | INFOPLIST_FILE = "MVVM-C-App-Core-Networking/Info.plist"; 670 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 671 | LD_RUNPATH_SEARCH_PATHS = ( 672 | "$(inherited)", 673 | "@executable_path/Frameworks", 674 | ); 675 | PRODUCT_BUNDLE_IDENTIFIER = "com.oguzparlak.MVVM-C-App-Core-Networking"; 676 | PRODUCT_NAME = "$(TARGET_NAME)"; 677 | SWIFT_VERSION = 5.0; 678 | TARGETED_DEVICE_FAMILY = "1,2"; 679 | }; 680 | name = Release; 681 | }; 682 | BF5EC3FF22C527940068A24C /* Debug */ = { 683 | isa = XCBuildConfiguration; 684 | buildSettings = { 685 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 686 | BUNDLE_LOADER = "$(TEST_HOST)"; 687 | CODE_SIGN_STYLE = Automatic; 688 | DEVELOPMENT_TEAM = HL7GD8S24Y; 689 | INFOPLIST_FILE = "MVVM-C-App-Core-NetworkingTests/Info.plist"; 690 | LD_RUNPATH_SEARCH_PATHS = ( 691 | "$(inherited)", 692 | "@executable_path/Frameworks", 693 | "@loader_path/Frameworks", 694 | ); 695 | PRODUCT_BUNDLE_IDENTIFIER = "com.oguzparlak.MVVM-C-App-Core-NetworkingTests"; 696 | PRODUCT_NAME = "$(TARGET_NAME)"; 697 | SWIFT_VERSION = 5.0; 698 | TARGETED_DEVICE_FAMILY = "1,2"; 699 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MVVM-C-App-Core-Networking.app/MVVM-C-App-Core-Networking"; 700 | }; 701 | name = Debug; 702 | }; 703 | BF5EC40022C527940068A24C /* Release */ = { 704 | isa = XCBuildConfiguration; 705 | buildSettings = { 706 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 707 | BUNDLE_LOADER = "$(TEST_HOST)"; 708 | CODE_SIGN_STYLE = Automatic; 709 | DEVELOPMENT_TEAM = HL7GD8S24Y; 710 | INFOPLIST_FILE = "MVVM-C-App-Core-NetworkingTests/Info.plist"; 711 | LD_RUNPATH_SEARCH_PATHS = ( 712 | "$(inherited)", 713 | "@executable_path/Frameworks", 714 | "@loader_path/Frameworks", 715 | ); 716 | PRODUCT_BUNDLE_IDENTIFIER = "com.oguzparlak.MVVM-C-App-Core-NetworkingTests"; 717 | PRODUCT_NAME = "$(TARGET_NAME)"; 718 | SWIFT_VERSION = 5.0; 719 | TARGETED_DEVICE_FAMILY = "1,2"; 720 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MVVM-C-App-Core-Networking.app/MVVM-C-App-Core-Networking"; 721 | }; 722 | name = Release; 723 | }; 724 | BF5EC40222C527940068A24C /* Debug */ = { 725 | isa = XCBuildConfiguration; 726 | buildSettings = { 727 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 728 | CODE_SIGN_STYLE = Automatic; 729 | DEVELOPMENT_TEAM = HL7GD8S24Y; 730 | INFOPLIST_FILE = "MVVM-C-App-Core-NetworkingUITests/Info.plist"; 731 | LD_RUNPATH_SEARCH_PATHS = ( 732 | "$(inherited)", 733 | "@executable_path/Frameworks", 734 | "@loader_path/Frameworks", 735 | ); 736 | PRODUCT_BUNDLE_IDENTIFIER = "com.oguzparlak.MVVM-C-App-Core-NetworkingUITests"; 737 | PRODUCT_NAME = "$(TARGET_NAME)"; 738 | SWIFT_VERSION = 5.0; 739 | TARGETED_DEVICE_FAMILY = "1,2"; 740 | TEST_TARGET_NAME = "MVVM-C-App-Core-Networking"; 741 | }; 742 | name = Debug; 743 | }; 744 | BF5EC40322C527940068A24C /* Release */ = { 745 | isa = XCBuildConfiguration; 746 | buildSettings = { 747 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 748 | CODE_SIGN_STYLE = Automatic; 749 | DEVELOPMENT_TEAM = HL7GD8S24Y; 750 | INFOPLIST_FILE = "MVVM-C-App-Core-NetworkingUITests/Info.plist"; 751 | LD_RUNPATH_SEARCH_PATHS = ( 752 | "$(inherited)", 753 | "@executable_path/Frameworks", 754 | "@loader_path/Frameworks", 755 | ); 756 | PRODUCT_BUNDLE_IDENTIFIER = "com.oguzparlak.MVVM-C-App-Core-NetworkingUITests"; 757 | PRODUCT_NAME = "$(TARGET_NAME)"; 758 | SWIFT_VERSION = 5.0; 759 | TARGETED_DEVICE_FAMILY = "1,2"; 760 | TEST_TARGET_NAME = "MVVM-C-App-Core-Networking"; 761 | }; 762 | name = Release; 763 | }; 764 | /* End XCBuildConfiguration section */ 765 | 766 | /* Begin XCConfigurationList section */ 767 | BF5EC3CE22C527940068A24C /* Build configuration list for PBXProject "MVVM-C-App-Core-Networking" */ = { 768 | isa = XCConfigurationList; 769 | buildConfigurations = ( 770 | BF5EC3F922C527940068A24C /* Debug */, 771 | BF5EC3FA22C527940068A24C /* Release */, 772 | ); 773 | defaultConfigurationIsVisible = 0; 774 | defaultConfigurationName = Release; 775 | }; 776 | BF5EC3FB22C527940068A24C /* Build configuration list for PBXNativeTarget "MVVM-C-App-Core-Networking" */ = { 777 | isa = XCConfigurationList; 778 | buildConfigurations = ( 779 | BF5EC3FC22C527940068A24C /* Debug */, 780 | BF5EC3FD22C527940068A24C /* Release */, 781 | ); 782 | defaultConfigurationIsVisible = 0; 783 | defaultConfigurationName = Release; 784 | }; 785 | BF5EC3FE22C527940068A24C /* Build configuration list for PBXNativeTarget "MVVM-C-App-Core-NetworkingTests" */ = { 786 | isa = XCConfigurationList; 787 | buildConfigurations = ( 788 | BF5EC3FF22C527940068A24C /* Debug */, 789 | BF5EC40022C527940068A24C /* Release */, 790 | ); 791 | defaultConfigurationIsVisible = 0; 792 | defaultConfigurationName = Release; 793 | }; 794 | BF5EC40122C527940068A24C /* Build configuration list for PBXNativeTarget "MVVM-C-App-Core-NetworkingUITests" */ = { 795 | isa = XCConfigurationList; 796 | buildConfigurations = ( 797 | BF5EC40222C527940068A24C /* Debug */, 798 | BF5EC40322C527940068A24C /* Release */, 799 | ); 800 | defaultConfigurationIsVisible = 0; 801 | defaultConfigurationName = Release; 802 | }; 803 | /* End XCConfigurationList section */ 804 | }; 805 | rootObject = BF5EC3CB22C527940068A24C /* Project object */; 806 | } 807 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking.xcodeproj/project.xcworkspace/xcuserdata/oguzparlak.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking.xcodeproj/project.xcworkspace/xcuserdata/oguzparlak.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking.xcodeproj/xcuserdata/oguzparlak.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MVVM-C-App-Core-Networking.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 6 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking.xcworkspace/xcuserdata/oguzparlak.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking.xcworkspace/xcuserdata/oguzparlak.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking/.DS_Store -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/color_dark_bg.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0x2C", 13 | "alpha" : "1.000", 14 | "blue" : "0x50", 15 | "green" : "0x3E" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/color_theme.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.545", 13 | "alpha" : "1.000", 14 | "blue" : "0.290", 15 | "green" : "0.765" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icons8-tv-show-100.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icons8-tv-show-100@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icons8-tv-show-100@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "original" 25 | } 26 | } -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular.imageset/icons8-tv-show-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular.imageset/icons8-tv-show-100.png -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular.imageset/icons8-tv-show-100@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular.imageset/icons8-tv-show-100@2x.png -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular.imageset/icons8-tv-show-100@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular.imageset/icons8-tv-show-100@3x.png -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular_disabled.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icons8-tv-show-100.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icons8-tv-show-100@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icons8-tv-show-100@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "original" 25 | } 26 | } -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular_disabled.imageset/icons8-tv-show-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular_disabled.imageset/icons8-tv-show-100.png -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular_disabled.imageset/icons8-tv-show-100@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular_disabled.imageset/icons8-tv-show-100@2x.png -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular_disabled.imageset/icons8-tv-show-100@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking/Assets.xcassets/ic_popular_disabled.imageset/icons8-tv-show-100@3x.png -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_star.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icons8-star-90.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icons8-star-90@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icons8-star-90@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "original" 25 | } 26 | } -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_star.imageset/icons8-star-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking/Assets.xcassets/ic_star.imageset/icons8-star-90.png -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_star.imageset/icons8-star-90@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking/Assets.xcassets/ic_star.imageset/icons8-star-90@2x.png -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Assets.xcassets/ic_star.imageset/icons8-star-90@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/MVVM-C-App-Core-Networking/Assets.xcassets/ic_star.imageset/icons8-star-90@3x.png -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/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 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Coordinator/TVShowListingCoordinator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShowListingCoordinator.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Core 11 | 12 | class TVShowListingCoordinator: ConcreteCoordinator { 13 | 14 | override func start() { 15 | let listingView = TVShowListingView.instantiate() 16 | listingView.coordinator = self 17 | listingView.title = "Backlight" 18 | listingView.tabBarItem = UITabBarItem(title: "Popular", image: UIImage(named: "ic_popular_disabled"), selectedImage: UIImage(named: "ic_popular")) 19 | navigationController.pushViewController(listingView, animated: true) 20 | navigationController.configureTheme() 21 | } 22 | 23 | func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { 24 | if childCoordinatorShouldNotBeDeleted(navigationController: navigationController) { return } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Data/TVShowDataManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShowDataManager.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Core 11 | 12 | class TVShowDataManager: KeyValueManager { 13 | 14 | // MARK: - Initializer 15 | override init(dataNotifier: DataNotifier?) { 16 | super.init(dataNotifier: dataNotifier) 17 | } 18 | 19 | // MARK: - Public methods 20 | func loadAllTVShows() -> TVShowContainer? { 21 | return self.load(with: "tv_shows") 22 | } 23 | 24 | func saveAllTVShows(data: TVShowContainer?) { 25 | self.save(with: "tv_shows", data: data) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Extension/TVShowListView+UITableViewDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShowListView+UITableViewDelegate.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension TVShowListingView: UITableViewDelegate { 13 | 14 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 15 | // TODO 16 | } 17 | 18 | func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { 19 | return UIView() 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Extension/TVShowListingView+TVShowInteractor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShowListingView+Interactions.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension TVShowListingView: TVShowInteractor { 12 | 13 | func shouldUpdateTableView() { 14 | tableView.reloadData() 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Extension/TVShowListingView+UITableViewDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShowListingView+UITableViewDataSource.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension TVShowListingView: UITableViewDataSource { 13 | 14 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 15 | return tvShowViewModel?.tvShowCellViewModels.count ?? 0 16 | } 17 | 18 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 19 | let tvShowView = tableView.dequeueReusableCell(withIdentifier: "MovieListingCell") as! MovieListingCell 20 | let tvShowViewModels = tvShowViewModel?.tvShowCellViewModels 21 | let currentIndex = indexPath.row 22 | let tvShowCellViewModel = tvShowViewModels?[currentIndex] 23 | tvShowView.tvShowViewModel = tvShowCellViewModel 24 | return tvShowView 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Extension/TVShowListingView+UITableViewDataSourcePrefetching.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShowListingView+UITableViewDataSourcePrefetching.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 4.07.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension TVShowListingView: UITableViewDataSourcePrefetching { 13 | 14 | func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { 15 | guard let tvShowViewModels: [TVShowCellViewModel] = tvShowViewModel?.tvShowCellViewModels else { return } 16 | let shouldFetchRemoteData: Bool = indexPaths.contains { (indexPath) -> Bool in 17 | // If there is 5 more rows to go, than start fetching data from remote 18 | indexPath.row == tvShowViewModels.count - 5 19 | } 20 | if shouldFetchRemoteData { 21 | tvShowViewModel?.fetchTVShows(shouldApplyPagination: true) 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIMainStoryboardFile 31 | Main 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UIStatusBarStyle 37 | UIStatusBarStyleLightContent 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Interactor/TVShowInteractor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShowInteractor.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol TVShowInteractor { 12 | 13 | func shouldUpdateTableView() 14 | 15 | } 16 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Model/TVShow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShow.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct TVShow: Codable { 12 | 13 | var originalName: String? 14 | var id: Int? 15 | var name: String? 16 | var voteCount: Int? 17 | var voteAverage: Double? 18 | var firstAirDate: String? 19 | var posterPath: String? 20 | var genreIds: [Int]? 21 | var originalLanguage: String? 22 | var backdropPath: String? 23 | var overview: String? 24 | var originCountry: [String]? 25 | var popularity: Double? 26 | 27 | private enum CodingKeys : String, CodingKey { 28 | case originalName = "original_name" 29 | case id = "id" 30 | case name = "name" 31 | case voteCount = "vote_count" 32 | case voteAverage = "vote_average" 33 | case firstAirDate = "first_air_date" 34 | case posterPath = "poster_path" 35 | case genreIds = "genre_ids" 36 | case originalLanguage = "original_language" 37 | case backdropPath = "backdrop_path" 38 | case overview = "overview" 39 | case originCountry = "origin_country" 40 | case popularity = "popularity" 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Model/TVShowContainer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShowContainer.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct TVShowContainer: Codable { 12 | 13 | var page: Int? 14 | var results: [TVShow]? 15 | var totalPages: Int? 16 | var totalResults: Int? 17 | 18 | private enum CodingKeys: String, CodingKey { 19 | case page = "page" 20 | case results = "results" 21 | case totalPages = "total_pages" 22 | case totalResults = "total_results" 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Networking/TVShowEndPoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MovieEndPoint.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Networking 11 | 12 | /// Models the TVShowEndPoint 13 | enum TVShowEndPoint : EndpointProvider { 14 | 15 | // Gathers popular tv shows weekly or daily 16 | case trendingTvShows(timeWindow: String) 17 | case image(width: String, posterPath: String) 18 | 19 | // MARK: - EndPointProvider conforming methods 20 | 21 | func provideUrl() -> String { 22 | 23 | switch self { 24 | case .trendingTvShows(let timeWindow): 25 | return "trending/tv/\(timeWindow)" 26 | case .image(let width, let posterPath): 27 | return "https://image.tmdb.org/t/p/w\(width)/\(posterPath)" 28 | } 29 | } 30 | 31 | // MARK: - Private methods 32 | 33 | private func parameters(for page: Int) -> [String : String] { 34 | return [ 35 | "page" : String(page) 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/Repository/TVShowRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShowRepository.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Networking 11 | import Core 12 | 13 | class TVShowRepository: Repository { 14 | 15 | typealias T = TVShowContainer? 16 | 17 | private var requestConfigurator: RequestConfigurator 18 | 19 | private var dataManager: TVShowDataManager? 20 | 21 | private var currentPage: Int = 1 { 22 | didSet { 23 | requestConfigurator.parameters = [ 24 | "page" : String(currentPage), 25 | Constants.Parameters.api_key: Constants.tmdbApiKey] 26 | } 27 | } 28 | 29 | func incrementPage() { 30 | currentPage += 1 31 | } 32 | 33 | public init(requestConfigurator: RequestConfigurator, dataManager: TVShowDataManager? = TVShowDataManager(dataNotifier: DataNotifier(dataCallback: { (container) in 34 | 35 | }, errorCallback: { (error) in 36 | 37 | }))) { 38 | self.dataManager = dataManager 39 | self.requestConfigurator = requestConfigurator 40 | } 41 | 42 | func getLocalDataSource() -> TVShowContainer? { 43 | return dataManager?.loadAllTVShows() 44 | } 45 | 46 | func getRemoteDataSource(responseCallback: @escaping (Result) -> Void) { 47 | ApiClient.request(ApiRouter(requestConfigurator: requestConfigurator), completion: responseCallback) 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/View/MovieListingCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MovieListingCell.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Kingfisher 11 | 12 | class MovieListingCell: UITableViewCell { 13 | 14 | @IBOutlet weak var posterImageView: UIImageView! 15 | @IBOutlet weak var titleLabel: UILabel! 16 | @IBOutlet weak var overviewLabel: UILabel! 17 | @IBOutlet weak var voteLabel: UILabel! 18 | 19 | var tvShowViewModel: TVShowCellViewModel? { 20 | didSet { 21 | updateUI() 22 | } 23 | } 24 | 25 | override func awakeFromNib() { 26 | super.awakeFromNib() 27 | // Initialization code 28 | } 29 | 30 | func updateUI() { 31 | // Bind labels 32 | titleLabel.text = tvShowViewModel?.title 33 | overviewLabel.text = tvShowViewModel?.overview 34 | voteLabel.text = tvShowViewModel?.voteDescription 35 | // Bind Image 36 | let posterPath = tvShowViewModel?.backdropPath 37 | let imageUrl = TVShowEndPoint 38 | .image(width: String(500), 39 | posterPath: posterPath ?? "") 40 | .provideUrl() 41 | posterImageView.kf.setImage(with: URL(string: imageUrl)) 42 | posterImageView.kf.indicatorType = .activity 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/View/MovieListingCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 50 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/View/TVShowListingView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Core 11 | 12 | class TVShowListingView: UIViewController, Storyboarded { 13 | 14 | 15 | // MARK: - UI Elements 16 | 17 | @IBOutlet weak var tableView: UITableView! 18 | 19 | // MARK: - Public Variables 20 | 21 | weak var coordinator: TVShowListingCoordinator? 22 | var tvShowViewModel: TVShowViewModel? 23 | 24 | // MARK: - Methods 25 | func initTableView() { 26 | tableView.delegate = self 27 | tableView.dataSource = self 28 | tableView.prefetchDataSource = self 29 | tableView.rowHeight = UITableView.automaticDimension 30 | tableView.backgroundColor = .black 31 | tableView.register(UINib(nibName: "MovieListingCell", bundle: nil), forCellReuseIdentifier: "MovieListingCell") 32 | } 33 | 34 | } 35 | 36 | // MARK: - Lifecycle 37 | extension TVShowListingView { 38 | 39 | override func viewDidLoad() { 40 | super.viewDidLoad() 41 | // Do any additional setup after loading the view. 42 | tvShowViewModel = TVShowViewModel(tvShowInteractor: self) 43 | initTableView() 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/ViewModel/TVShowCellViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShowCellViewModel.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class TVShowCellViewModel { 12 | 13 | private let tvShow: TVShow 14 | 15 | var title: String? { 16 | get { 17 | return tvShow.name 18 | } 19 | } 20 | 21 | var overview: String? { 22 | get { 23 | return tvShow.overview 24 | } 25 | } 26 | 27 | var posterPath: String? { 28 | get { 29 | return tvShow.posterPath 30 | } 31 | } 32 | 33 | var backdropPath: String? { 34 | get { 35 | return tvShow.backdropPath 36 | } 37 | } 38 | 39 | var voteDescription: String? { 40 | get { 41 | return "\(tvShow.voteAverage!) / 10 (\(tvShow.voteCount!) total votes)" 42 | } 43 | } 44 | 45 | init(tvShow: TVShow) { 46 | self.tvShow = tvShow 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /MVVM-C-App-Core-Networking/ViewModel/TVShowViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TVShowViewModel.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Core 11 | import Networking 12 | 13 | class TVShowViewModel { 14 | 15 | var tvShowContainer: TVShowContainer? { 16 | didSet { 17 | // Update UI 18 | updateCellViewModels() 19 | tvShowInteractor.shouldUpdateTableView() 20 | } 21 | } 22 | 23 | var tvShowCellViewModels: [TVShowCellViewModel] = [] 24 | 25 | private let tvShowRepository: TVShowRepository 26 | private let tvShowInteractor: TVShowInteractor 27 | 28 | init(tvShowRepository: TVShowRepository = TVShowRepository(requestConfigurator: RequestConfigurator(path: TVShowEndPoint.trendingTvShows(timeWindow: "week").provideUrl(), parameters: [Constants.Parameters.api_key : Constants.tmdbApiKey])), tvShowInteractor: TVShowInteractor) { 29 | self.tvShowRepository = tvShowRepository 30 | self.tvShowInteractor = tvShowInteractor 31 | fetchTVShows() 32 | } 33 | 34 | func fetchTVShows(shouldApplyPagination: Bool = false) { 35 | if shouldApplyPagination { tvShowRepository.incrementPage() } 36 | self.tvShowRepository.getRemoteDataSource(responseCallback: { [weak self] result in 37 | switch result { 38 | case .success(let tvShows): 39 | self?.tvShowContainer = tvShows 40 | case .error(let error): 41 | print(error) 42 | } 43 | }) 44 | } 45 | 46 | func updateCellViewModels() { 47 | let tvShows = tvShowContainer?.results ?? [] 48 | for tvShow in tvShows { 49 | tvShowCellViewModels.append(TVShowCellViewModel(tvShow: tvShow)) 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Networking/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oguzparlak/MVVM-C-Networking-AppCore/fa73d2811557da9baec03564596f061be599a380/Networking/.DS_Store -------------------------------------------------------------------------------- /Networking/Networking.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B39647A9CDFEDEB2849BF7AB /* Pods_Networking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 149B113FA77B37497D09AB7D /* Pods_Networking.framework */; }; 11 | BF0BA6C322C8C56C00AA3CA3 /* EndpointProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0BA6C222C8C56C00AA3CA3 /* EndpointProvider.swift */; }; 12 | BF5EC44C22C529AA0068A24C /* Networking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF5EC44222C529AA0068A24C /* Networking.framework */; }; 13 | BF5EC45122C529AA0068A24C /* NetworkingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC45022C529AA0068A24C /* NetworkingTests.swift */; }; 14 | BF5EC45322C529AA0068A24C /* Networking.h in Headers */ = {isa = PBXBuildFile; fileRef = BF5EC44522C529AA0068A24C /* Networking.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | BF5EC48C22C55DB60068A24C /* RequestConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC48B22C55DB60068A24C /* RequestConfigurator.swift */; }; 16 | BF5EC48E22C55EA80068A24C /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC48D22C55EA80068A24C /* Constants.swift */; }; 17 | BF5EC49022C55ED80068A24C /* ApiRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC48F22C55ED80068A24C /* ApiRouter.swift */; }; 18 | BF5EC49222C55F0A0068A24C /* ApiError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC49122C55F0A0068A24C /* ApiError.swift */; }; 19 | BF5EC49422C55F2A0068A24C /* ApiClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC49322C55F2A0068A24C /* ApiClient.swift */; }; 20 | BF5EC49622C560410068A24C /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5EC49522C560410068A24C /* Reachability.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | BF5EC44D22C529AA0068A24C /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = BF5EC43922C529AA0068A24C /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = BF5EC44122C529AA0068A24C; 29 | remoteInfo = Networking; 30 | }; 31 | /* End PBXContainerItemProxy section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 149B113FA77B37497D09AB7D /* Pods_Networking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Networking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | 54D8CEC14DF8502982911048 /* Pods-Networking.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Networking.release.xcconfig"; path = "../Pods/Target Support Files/Pods-Networking/Pods-Networking.release.xcconfig"; sourceTree = ""; }; 36 | BF0BA6C222C8C56C00AA3CA3 /* EndpointProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndpointProvider.swift; sourceTree = ""; }; 37 | BF5EC44222C529AA0068A24C /* Networking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Networking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | BF5EC44522C529AA0068A24C /* Networking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Networking.h; sourceTree = ""; }; 39 | BF5EC44622C529AA0068A24C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | BF5EC44B22C529AA0068A24C /* NetworkingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NetworkingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | BF5EC45022C529AA0068A24C /* NetworkingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkingTests.swift; sourceTree = ""; }; 42 | BF5EC45222C529AA0068A24C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43 | BF5EC48B22C55DB60068A24C /* RequestConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestConfigurator.swift; sourceTree = ""; }; 44 | BF5EC48D22C55EA80068A24C /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 45 | BF5EC48F22C55ED80068A24C /* ApiRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiRouter.swift; sourceTree = ""; }; 46 | BF5EC49122C55F0A0068A24C /* ApiError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiError.swift; sourceTree = ""; }; 47 | BF5EC49322C55F2A0068A24C /* ApiClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiClient.swift; sourceTree = ""; }; 48 | BF5EC49522C560410068A24C /* Reachability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reachability.swift; sourceTree = ""; }; 49 | F0BC82450D43EDC58BD5D5C7 /* Pods-Networking.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Networking.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-Networking/Pods-Networking.debug.xcconfig"; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | BF5EC43F22C529AA0068A24C /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | B39647A9CDFEDEB2849BF7AB /* Pods_Networking.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | BF5EC44822C529AA0068A24C /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | BF5EC44C22C529AA0068A24C /* Networking.framework in Frameworks */, 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXFrameworksBuildPhase section */ 70 | 71 | /* Begin PBXGroup section */ 72 | A4670897EA0F6361F5EE57E0 /* Frameworks */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 149B113FA77B37497D09AB7D /* Pods_Networking.framework */, 76 | ); 77 | name = Frameworks; 78 | sourceTree = ""; 79 | }; 80 | BF5EC43822C529AA0068A24C = { 81 | isa = PBXGroup; 82 | children = ( 83 | BF5EC44422C529AA0068A24C /* Networking */, 84 | BF5EC44F22C529AA0068A24C /* NetworkingTests */, 85 | BF5EC44322C529AA0068A24C /* Products */, 86 | DFB9E75D04E850C28D3D6D2A /* Pods */, 87 | A4670897EA0F6361F5EE57E0 /* Frameworks */, 88 | ); 89 | sourceTree = ""; 90 | }; 91 | BF5EC44322C529AA0068A24C /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | BF5EC44222C529AA0068A24C /* Networking.framework */, 95 | BF5EC44B22C529AA0068A24C /* NetworkingTests.xctest */, 96 | ); 97 | name = Products; 98 | sourceTree = ""; 99 | }; 100 | BF5EC44422C529AA0068A24C /* Networking */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | BF5EC44522C529AA0068A24C /* Networking.h */, 104 | BF5EC44622C529AA0068A24C /* Info.plist */, 105 | BF5EC48B22C55DB60068A24C /* RequestConfigurator.swift */, 106 | BF5EC48D22C55EA80068A24C /* Constants.swift */, 107 | BF5EC48F22C55ED80068A24C /* ApiRouter.swift */, 108 | BF5EC49122C55F0A0068A24C /* ApiError.swift */, 109 | BF5EC49322C55F2A0068A24C /* ApiClient.swift */, 110 | BF5EC49522C560410068A24C /* Reachability.swift */, 111 | BF0BA6C222C8C56C00AA3CA3 /* EndpointProvider.swift */, 112 | ); 113 | path = Networking; 114 | sourceTree = ""; 115 | }; 116 | BF5EC44F22C529AA0068A24C /* NetworkingTests */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | BF5EC45022C529AA0068A24C /* NetworkingTests.swift */, 120 | BF5EC45222C529AA0068A24C /* Info.plist */, 121 | ); 122 | path = NetworkingTests; 123 | sourceTree = ""; 124 | }; 125 | DFB9E75D04E850C28D3D6D2A /* Pods */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | F0BC82450D43EDC58BD5D5C7 /* Pods-Networking.debug.xcconfig */, 129 | 54D8CEC14DF8502982911048 /* Pods-Networking.release.xcconfig */, 130 | ); 131 | name = Pods; 132 | sourceTree = ""; 133 | }; 134 | /* End PBXGroup section */ 135 | 136 | /* Begin PBXHeadersBuildPhase section */ 137 | BF5EC43D22C529AA0068A24C /* Headers */ = { 138 | isa = PBXHeadersBuildPhase; 139 | buildActionMask = 2147483647; 140 | files = ( 141 | BF5EC45322C529AA0068A24C /* Networking.h in Headers */, 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | /* End PBXHeadersBuildPhase section */ 146 | 147 | /* Begin PBXNativeTarget section */ 148 | BF5EC44122C529AA0068A24C /* Networking */ = { 149 | isa = PBXNativeTarget; 150 | buildConfigurationList = BF5EC45622C529AA0068A24C /* Build configuration list for PBXNativeTarget "Networking" */; 151 | buildPhases = ( 152 | E053887CE81E5E50D88BB342 /* [CP] Check Pods Manifest.lock */, 153 | BF5EC43D22C529AA0068A24C /* Headers */, 154 | BF5EC43E22C529AA0068A24C /* Sources */, 155 | BF5EC43F22C529AA0068A24C /* Frameworks */, 156 | BF5EC44022C529AA0068A24C /* Resources */, 157 | ); 158 | buildRules = ( 159 | ); 160 | dependencies = ( 161 | ); 162 | name = Networking; 163 | productName = Networking; 164 | productReference = BF5EC44222C529AA0068A24C /* Networking.framework */; 165 | productType = "com.apple.product-type.framework"; 166 | }; 167 | BF5EC44A22C529AA0068A24C /* NetworkingTests */ = { 168 | isa = PBXNativeTarget; 169 | buildConfigurationList = BF5EC45922C529AA0068A24C /* Build configuration list for PBXNativeTarget "NetworkingTests" */; 170 | buildPhases = ( 171 | BF5EC44722C529AA0068A24C /* Sources */, 172 | BF5EC44822C529AA0068A24C /* Frameworks */, 173 | BF5EC44922C529AA0068A24C /* Resources */, 174 | ); 175 | buildRules = ( 176 | ); 177 | dependencies = ( 178 | BF5EC44E22C529AA0068A24C /* PBXTargetDependency */, 179 | ); 180 | name = NetworkingTests; 181 | productName = NetworkingTests; 182 | productReference = BF5EC44B22C529AA0068A24C /* NetworkingTests.xctest */; 183 | productType = "com.apple.product-type.bundle.unit-test"; 184 | }; 185 | /* End PBXNativeTarget section */ 186 | 187 | /* Begin PBXProject section */ 188 | BF5EC43922C529AA0068A24C /* Project object */ = { 189 | isa = PBXProject; 190 | attributes = { 191 | LastSwiftUpdateCheck = 1020; 192 | LastUpgradeCheck = 1020; 193 | ORGANIZATIONNAME = "Oguz Parlak"; 194 | TargetAttributes = { 195 | BF5EC44122C529AA0068A24C = { 196 | CreatedOnToolsVersion = 10.2.1; 197 | LastSwiftMigration = 1020; 198 | }; 199 | BF5EC44A22C529AA0068A24C = { 200 | CreatedOnToolsVersion = 10.2.1; 201 | }; 202 | }; 203 | }; 204 | buildConfigurationList = BF5EC43C22C529AA0068A24C /* Build configuration list for PBXProject "Networking" */; 205 | compatibilityVersion = "Xcode 9.3"; 206 | developmentRegion = en; 207 | hasScannedForEncodings = 0; 208 | knownRegions = ( 209 | en, 210 | ); 211 | mainGroup = BF5EC43822C529AA0068A24C; 212 | productRefGroup = BF5EC44322C529AA0068A24C /* Products */; 213 | projectDirPath = ""; 214 | projectRoot = ""; 215 | targets = ( 216 | BF5EC44122C529AA0068A24C /* Networking */, 217 | BF5EC44A22C529AA0068A24C /* NetworkingTests */, 218 | ); 219 | }; 220 | /* End PBXProject section */ 221 | 222 | /* Begin PBXResourcesBuildPhase section */ 223 | BF5EC44022C529AA0068A24C /* Resources */ = { 224 | isa = PBXResourcesBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | ); 228 | runOnlyForDeploymentPostprocessing = 0; 229 | }; 230 | BF5EC44922C529AA0068A24C /* Resources */ = { 231 | isa = PBXResourcesBuildPhase; 232 | buildActionMask = 2147483647; 233 | files = ( 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | }; 237 | /* End PBXResourcesBuildPhase section */ 238 | 239 | /* Begin PBXShellScriptBuildPhase section */ 240 | E053887CE81E5E50D88BB342 /* [CP] Check Pods Manifest.lock */ = { 241 | isa = PBXShellScriptBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | ); 245 | inputFileListPaths = ( 246 | ); 247 | inputPaths = ( 248 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 249 | "${PODS_ROOT}/Manifest.lock", 250 | ); 251 | name = "[CP] Check Pods Manifest.lock"; 252 | outputFileListPaths = ( 253 | ); 254 | outputPaths = ( 255 | "$(DERIVED_FILE_DIR)/Pods-Networking-checkManifestLockResult.txt", 256 | ); 257 | runOnlyForDeploymentPostprocessing = 0; 258 | shellPath = /bin/sh; 259 | 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"; 260 | showEnvVarsInLog = 0; 261 | }; 262 | /* End PBXShellScriptBuildPhase section */ 263 | 264 | /* Begin PBXSourcesBuildPhase section */ 265 | BF5EC43E22C529AA0068A24C /* Sources */ = { 266 | isa = PBXSourcesBuildPhase; 267 | buildActionMask = 2147483647; 268 | files = ( 269 | BF5EC48C22C55DB60068A24C /* RequestConfigurator.swift in Sources */, 270 | BF5EC49222C55F0A0068A24C /* ApiError.swift in Sources */, 271 | BF5EC49622C560410068A24C /* Reachability.swift in Sources */, 272 | BF0BA6C322C8C56C00AA3CA3 /* EndpointProvider.swift in Sources */, 273 | BF5EC49022C55ED80068A24C /* ApiRouter.swift in Sources */, 274 | BF5EC48E22C55EA80068A24C /* Constants.swift in Sources */, 275 | BF5EC49422C55F2A0068A24C /* ApiClient.swift in Sources */, 276 | ); 277 | runOnlyForDeploymentPostprocessing = 0; 278 | }; 279 | BF5EC44722C529AA0068A24C /* Sources */ = { 280 | isa = PBXSourcesBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | BF5EC45122C529AA0068A24C /* NetworkingTests.swift in Sources */, 284 | ); 285 | runOnlyForDeploymentPostprocessing = 0; 286 | }; 287 | /* End PBXSourcesBuildPhase section */ 288 | 289 | /* Begin PBXTargetDependency section */ 290 | BF5EC44E22C529AA0068A24C /* PBXTargetDependency */ = { 291 | isa = PBXTargetDependency; 292 | target = BF5EC44122C529AA0068A24C /* Networking */; 293 | targetProxy = BF5EC44D22C529AA0068A24C /* PBXContainerItemProxy */; 294 | }; 295 | /* End PBXTargetDependency section */ 296 | 297 | /* Begin XCBuildConfiguration section */ 298 | BF5EC45422C529AA0068A24C /* Debug */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | ALWAYS_SEARCH_USER_PATHS = NO; 302 | CLANG_ANALYZER_NONNULL = YES; 303 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 304 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 305 | CLANG_CXX_LIBRARY = "libc++"; 306 | CLANG_ENABLE_MODULES = YES; 307 | CLANG_ENABLE_OBJC_ARC = YES; 308 | CLANG_ENABLE_OBJC_WEAK = YES; 309 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 310 | CLANG_WARN_BOOL_CONVERSION = YES; 311 | CLANG_WARN_COMMA = YES; 312 | CLANG_WARN_CONSTANT_CONVERSION = YES; 313 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 314 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 315 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 316 | CLANG_WARN_EMPTY_BODY = YES; 317 | CLANG_WARN_ENUM_CONVERSION = YES; 318 | CLANG_WARN_INFINITE_RECURSION = YES; 319 | CLANG_WARN_INT_CONVERSION = YES; 320 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 321 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 324 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 325 | CLANG_WARN_STRICT_PROTOTYPES = YES; 326 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 327 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | CODE_SIGN_IDENTITY = "iPhone Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | CURRENT_PROJECT_VERSION = 1; 333 | DEBUG_INFORMATION_FORMAT = dwarf; 334 | ENABLE_STRICT_OBJC_MSGSEND = YES; 335 | ENABLE_TESTABILITY = YES; 336 | GCC_C_LANGUAGE_STANDARD = gnu11; 337 | GCC_DYNAMIC_NO_PIC = NO; 338 | GCC_NO_COMMON_BLOCKS = YES; 339 | GCC_OPTIMIZATION_LEVEL = 0; 340 | GCC_PREPROCESSOR_DEFINITIONS = ( 341 | "DEBUG=1", 342 | "$(inherited)", 343 | ); 344 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 345 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 346 | GCC_WARN_UNDECLARED_SELECTOR = YES; 347 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 348 | GCC_WARN_UNUSED_FUNCTION = YES; 349 | GCC_WARN_UNUSED_VARIABLE = YES; 350 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 351 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 352 | MTL_FAST_MATH = YES; 353 | ONLY_ACTIVE_ARCH = YES; 354 | SDKROOT = iphoneos; 355 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 356 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 357 | VERSIONING_SYSTEM = "apple-generic"; 358 | VERSION_INFO_PREFIX = ""; 359 | }; 360 | name = Debug; 361 | }; 362 | BF5EC45522C529AA0068A24C /* Release */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | ALWAYS_SEARCH_USER_PATHS = NO; 366 | CLANG_ANALYZER_NONNULL = YES; 367 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 368 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 369 | CLANG_CXX_LIBRARY = "libc++"; 370 | CLANG_ENABLE_MODULES = YES; 371 | CLANG_ENABLE_OBJC_ARC = YES; 372 | CLANG_ENABLE_OBJC_WEAK = YES; 373 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 374 | CLANG_WARN_BOOL_CONVERSION = YES; 375 | CLANG_WARN_COMMA = YES; 376 | CLANG_WARN_CONSTANT_CONVERSION = YES; 377 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 378 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 379 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 380 | CLANG_WARN_EMPTY_BODY = YES; 381 | CLANG_WARN_ENUM_CONVERSION = YES; 382 | CLANG_WARN_INFINITE_RECURSION = YES; 383 | CLANG_WARN_INT_CONVERSION = YES; 384 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 385 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 386 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 387 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 388 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 389 | CLANG_WARN_STRICT_PROTOTYPES = YES; 390 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 391 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 392 | CLANG_WARN_UNREACHABLE_CODE = YES; 393 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 394 | CODE_SIGN_IDENTITY = "iPhone Developer"; 395 | COPY_PHASE_STRIP = NO; 396 | CURRENT_PROJECT_VERSION = 1; 397 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 398 | ENABLE_NS_ASSERTIONS = NO; 399 | ENABLE_STRICT_OBJC_MSGSEND = YES; 400 | GCC_C_LANGUAGE_STANDARD = gnu11; 401 | GCC_NO_COMMON_BLOCKS = YES; 402 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 403 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 404 | GCC_WARN_UNDECLARED_SELECTOR = YES; 405 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 406 | GCC_WARN_UNUSED_FUNCTION = YES; 407 | GCC_WARN_UNUSED_VARIABLE = YES; 408 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 409 | MTL_ENABLE_DEBUG_INFO = NO; 410 | MTL_FAST_MATH = YES; 411 | SDKROOT = iphoneos; 412 | SWIFT_COMPILATION_MODE = wholemodule; 413 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 414 | VALIDATE_PRODUCT = YES; 415 | VERSIONING_SYSTEM = "apple-generic"; 416 | VERSION_INFO_PREFIX = ""; 417 | }; 418 | name = Release; 419 | }; 420 | BF5EC45722C529AA0068A24C /* Debug */ = { 421 | isa = XCBuildConfiguration; 422 | baseConfigurationReference = F0BC82450D43EDC58BD5D5C7 /* Pods-Networking.debug.xcconfig */; 423 | buildSettings = { 424 | CLANG_ENABLE_MODULES = YES; 425 | CODE_SIGN_IDENTITY = ""; 426 | CODE_SIGN_STYLE = Automatic; 427 | DEFINES_MODULE = YES; 428 | DEVELOPMENT_TEAM = HL7GD8S24Y; 429 | DYLIB_COMPATIBILITY_VERSION = 1; 430 | DYLIB_CURRENT_VERSION = 1; 431 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 432 | INFOPLIST_FILE = Networking/Info.plist; 433 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 434 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 435 | LD_RUNPATH_SEARCH_PATHS = ( 436 | "$(inherited)", 437 | "@executable_path/Frameworks", 438 | "@loader_path/Frameworks", 439 | ); 440 | PRODUCT_BUNDLE_IDENTIFIER = com.oguzparlak.Networking; 441 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 442 | SKIP_INSTALL = YES; 443 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 444 | SWIFT_VERSION = 5.0; 445 | TARGETED_DEVICE_FAMILY = "1,2"; 446 | }; 447 | name = Debug; 448 | }; 449 | BF5EC45822C529AA0068A24C /* Release */ = { 450 | isa = XCBuildConfiguration; 451 | baseConfigurationReference = 54D8CEC14DF8502982911048 /* Pods-Networking.release.xcconfig */; 452 | buildSettings = { 453 | CLANG_ENABLE_MODULES = YES; 454 | CODE_SIGN_IDENTITY = ""; 455 | CODE_SIGN_STYLE = Automatic; 456 | DEFINES_MODULE = YES; 457 | DEVELOPMENT_TEAM = HL7GD8S24Y; 458 | DYLIB_COMPATIBILITY_VERSION = 1; 459 | DYLIB_CURRENT_VERSION = 1; 460 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 461 | INFOPLIST_FILE = Networking/Info.plist; 462 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 463 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 464 | LD_RUNPATH_SEARCH_PATHS = ( 465 | "$(inherited)", 466 | "@executable_path/Frameworks", 467 | "@loader_path/Frameworks", 468 | ); 469 | PRODUCT_BUNDLE_IDENTIFIER = com.oguzparlak.Networking; 470 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 471 | SKIP_INSTALL = YES; 472 | SWIFT_VERSION = 5.0; 473 | TARGETED_DEVICE_FAMILY = "1,2"; 474 | }; 475 | name = Release; 476 | }; 477 | BF5EC45A22C529AA0068A24C /* Debug */ = { 478 | isa = XCBuildConfiguration; 479 | buildSettings = { 480 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 481 | CODE_SIGN_STYLE = Automatic; 482 | DEVELOPMENT_TEAM = HL7GD8S24Y; 483 | INFOPLIST_FILE = NetworkingTests/Info.plist; 484 | LD_RUNPATH_SEARCH_PATHS = ( 485 | "$(inherited)", 486 | "@executable_path/Frameworks", 487 | "@loader_path/Frameworks", 488 | ); 489 | PRODUCT_BUNDLE_IDENTIFIER = com.oguzparlak.NetworkingTests; 490 | PRODUCT_NAME = "$(TARGET_NAME)"; 491 | SWIFT_VERSION = 5.0; 492 | TARGETED_DEVICE_FAMILY = "1,2"; 493 | }; 494 | name = Debug; 495 | }; 496 | BF5EC45B22C529AA0068A24C /* Release */ = { 497 | isa = XCBuildConfiguration; 498 | buildSettings = { 499 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 500 | CODE_SIGN_STYLE = Automatic; 501 | DEVELOPMENT_TEAM = HL7GD8S24Y; 502 | INFOPLIST_FILE = NetworkingTests/Info.plist; 503 | LD_RUNPATH_SEARCH_PATHS = ( 504 | "$(inherited)", 505 | "@executable_path/Frameworks", 506 | "@loader_path/Frameworks", 507 | ); 508 | PRODUCT_BUNDLE_IDENTIFIER = com.oguzparlak.NetworkingTests; 509 | PRODUCT_NAME = "$(TARGET_NAME)"; 510 | SWIFT_VERSION = 5.0; 511 | TARGETED_DEVICE_FAMILY = "1,2"; 512 | }; 513 | name = Release; 514 | }; 515 | /* End XCBuildConfiguration section */ 516 | 517 | /* Begin XCConfigurationList section */ 518 | BF5EC43C22C529AA0068A24C /* Build configuration list for PBXProject "Networking" */ = { 519 | isa = XCConfigurationList; 520 | buildConfigurations = ( 521 | BF5EC45422C529AA0068A24C /* Debug */, 522 | BF5EC45522C529AA0068A24C /* Release */, 523 | ); 524 | defaultConfigurationIsVisible = 0; 525 | defaultConfigurationName = Release; 526 | }; 527 | BF5EC45622C529AA0068A24C /* Build configuration list for PBXNativeTarget "Networking" */ = { 528 | isa = XCConfigurationList; 529 | buildConfigurations = ( 530 | BF5EC45722C529AA0068A24C /* Debug */, 531 | BF5EC45822C529AA0068A24C /* Release */, 532 | ); 533 | defaultConfigurationIsVisible = 0; 534 | defaultConfigurationName = Release; 535 | }; 536 | BF5EC45922C529AA0068A24C /* Build configuration list for PBXNativeTarget "NetworkingTests" */ = { 537 | isa = XCConfigurationList; 538 | buildConfigurations = ( 539 | BF5EC45A22C529AA0068A24C /* Debug */, 540 | BF5EC45B22C529AA0068A24C /* Release */, 541 | ); 542 | defaultConfigurationIsVisible = 0; 543 | defaultConfigurationName = Release; 544 | }; 545 | /* End XCConfigurationList section */ 546 | }; 547 | rootObject = BF5EC43922C529AA0068A24C /* Project object */; 548 | } 549 | -------------------------------------------------------------------------------- /Networking/Networking.xcodeproj/xcuserdata/oguzparlak.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Networking.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 5 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Networking/Networking/ApiClient.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ApiClient.swift 3 | // Networking 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | 12 | public enum Result where Failure: Error { 13 | case success(value: T) 14 | case error(error: Failure) 15 | } 16 | 17 | public class ApiClient { 18 | 19 | //------------------------------------------------------------------------------------------------- 20 | //MARK: - The request function to get results 21 | public static func request (_ urlConvertible: URLRequestConvertible, completion: @escaping (Result) -> Void) { 22 | //Trigger the HttpRequest using AlamoFire (AF) 23 | AF.request(urlConvertible).responseDecodable { (response: DataResponse) in 24 | //Check the result from Alamofire's response and check if it's a success or a failure 25 | switch response.result { 26 | case .success(let value): 27 | //Everything is fine 28 | completion(Result.success(value: value)) 29 | case .failure( _): 30 | //Something went wrong 31 | switch response.response?.statusCode { 32 | case 403: 33 | completion(Result.error(error: ApiError.forbidden)) 34 | case 404: 35 | completion(Result.error(error: ApiError.notFound)) 36 | case 409: 37 | completion(Result.error(error: ApiError.conflict)) 38 | case 500: 39 | completion(Result.error(error: ApiError.internalServerError)) 40 | default: 41 | completion(Result.error(error: ApiError.unknownError)) 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Networking/Networking/ApiError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ApiError.swift 3 | // Networking 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum ApiError: Error { 12 | case forbidden //Status code 403 13 | case notFound //Status code 404 14 | case conflict //Status code 409 15 | case internalServerError //Status code 500 16 | case unknownError //Status code not known 17 | } 18 | -------------------------------------------------------------------------------- /Networking/Networking/ApiRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ApiRouter.swift 3 | // Networking 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | 12 | public struct ApiRouter: URLRequestConvertible { 13 | 14 | private var requestConfigurator: RequestConfigurator 15 | 16 | public init(requestConfigurator: RequestConfigurator) { 17 | self.requestConfigurator = requestConfigurator 18 | } 19 | 20 | //MARK: - URLRequestConvertible 21 | public func asURLRequest() throws -> URLRequest { 22 | let url = try Constants.baseUrl.asURL() 23 | 24 | var urlRequest = URLRequest(url: url.appendingPathComponent(requestConfigurator.path!)) 25 | 26 | //Http method 27 | urlRequest.httpMethod = method.rawValue 28 | 29 | // Common Headers 30 | urlRequest.setValue(Constants.ContentType.json.rawValue, forHTTPHeaderField: Constants.HttpHeaderField.acceptType.rawValue) 31 | urlRequest.setValue(Constants.ContentType.json.rawValue, forHTTPHeaderField: Constants.HttpHeaderField.contentType.rawValue) 32 | 33 | //Encoding 34 | let encoding: ParameterEncoding = { 35 | switch method { 36 | case .get: 37 | return URLEncoding.default 38 | default: 39 | return JSONEncoding.default 40 | } 41 | }() 42 | 43 | return try encoding.encode(urlRequest, with: requestConfigurator.parameters!) 44 | } 45 | 46 | //MARK: - HttpMethod 47 | //This returns the HttpMethod type. It's used to determine the type if several endpoints are peresent 48 | private var method: HTTPMethod { 49 | return requestConfigurator.httpMethod! 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Networking/Networking/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // Networking 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Constants { 12 | 13 | /// The API's base URL 14 | public static let baseUrl = "https://api.themoviedb.org/3/" 15 | 16 | /// Paste your API Key over here 17 | public static let tmdbApiKey = "c5e241681c87e0206115395de7435e28" 18 | 19 | /// The parameters (Queries) that we're gonna use 20 | public struct Parameters { 21 | public static let api_key = "api_key" 22 | } 23 | 24 | /// The header fields 25 | public enum HttpHeaderField: String { 26 | case authentication = "Authorization" 27 | case contentType = "Content-Type" 28 | case acceptType = "Accept" 29 | case acceptEncoding = "Accept-Encoding" 30 | } 31 | 32 | /// The content type (JSON) 33 | public enum ContentType: String { 34 | case json = "application/json" 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Networking/Networking/EndpointProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EndpointProvider.swift 3 | // Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol EndpointProvider { 12 | 13 | func provideUrl() -> String 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Networking/Networking/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /Networking/Networking/Networking.h: -------------------------------------------------------------------------------- 1 | // 2 | // Networking.h 3 | // Networking 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Networking. 12 | FOUNDATION_EXPORT double NetworkingVersionNumber; 13 | 14 | //! Project version string for Networking. 15 | FOUNDATION_EXPORT const unsigned char NetworkingVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Networking/Networking/Reachability.swift: -------------------------------------------------------------------------------- 1 | import SystemConfiguration 2 | import Foundation 3 | 4 | public enum ReachabilityError: Error { 5 | case FailedToCreateWithAddress(sockaddr_in) 6 | case FailedToCreateWithHostname(String) 7 | case UnableToSetCallback 8 | case UnableToSetDispatchQueue 9 | case UnableToGetInitialFlags 10 | } 11 | 12 | @available(*, unavailable, renamed: "Notification.Name.reachabilityChanged") 13 | public let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification") 14 | 15 | public extension Notification.Name { 16 | static let reachabilityChanged = Notification.Name("reachabilityChanged") 17 | } 18 | 19 | public class Reachability { 20 | 21 | public typealias NetworkReachable = (Reachability) -> () 22 | public typealias NetworkUnreachable = (Reachability) -> () 23 | 24 | @available(*, unavailable, renamed: "Connection") 25 | public enum NetworkStatus: CustomStringConvertible { 26 | case notReachable, reachableViaWiFi, reachableViaWWAN 27 | public var description: String { 28 | switch self { 29 | case .reachableViaWWAN: return "Cellular" 30 | case .reachableViaWiFi: return "WiFi" 31 | case .notReachable: return "No Connection" 32 | } 33 | } 34 | } 35 | 36 | public enum Connection: CustomStringConvertible { 37 | case none, wifi, cellular 38 | public var description: String { 39 | switch self { 40 | case .cellular: return "Cellular" 41 | case .wifi: return "WiFi" 42 | case .none: return "No Connection" 43 | } 44 | } 45 | } 46 | 47 | public var whenReachable: NetworkReachable? 48 | public var whenUnreachable: NetworkUnreachable? 49 | 50 | @available(*, deprecated, renamed: "allowsCellularConnection") 51 | public let reachableOnWWAN: Bool = true 52 | 53 | /// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`) 54 | public var allowsCellularConnection: Bool 55 | 56 | // The notification center on which "reachability changed" events are being posted 57 | public var notificationCenter: NotificationCenter = NotificationCenter.default 58 | 59 | @available(*, deprecated, renamed: "connection.description") 60 | public var currentReachabilityString: String { 61 | return "\(connection)" 62 | } 63 | 64 | @available(*, unavailable, renamed: "connection") 65 | public var currentReachabilityStatus: Connection { 66 | return connection 67 | } 68 | 69 | public var connection: Connection { 70 | if flags == nil { 71 | try? setReachabilityFlags() 72 | } 73 | 74 | switch flags?.connection { 75 | case .none?, nil: return .none 76 | case .cellular?: return allowsCellularConnection ? .cellular : .none 77 | case .wifi?: return .wifi 78 | } 79 | } 80 | 81 | fileprivate var isRunningOnDevice: Bool = { 82 | #if targetEnvironment(simulator) 83 | return false 84 | #else 85 | return true 86 | #endif 87 | }() 88 | 89 | fileprivate var notifierRunning = false 90 | fileprivate let reachabilityRef: SCNetworkReachability 91 | fileprivate let reachabilitySerialQueue: DispatchQueue 92 | fileprivate(set) var flags: SCNetworkReachabilityFlags? { 93 | didSet { 94 | guard flags != oldValue else { return } 95 | reachabilityChanged() 96 | } 97 | } 98 | 99 | required public init(reachabilityRef: SCNetworkReachability, queueQoS: DispatchQoS = .default, targetQueue: DispatchQueue? = nil) { 100 | self.allowsCellularConnection = true 101 | self.reachabilityRef = reachabilityRef 102 | self.reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability", qos: queueQoS, target: targetQueue) 103 | } 104 | 105 | public convenience init?(hostname: String, queueQoS: DispatchQoS = .default, targetQueue: DispatchQueue? = nil) { 106 | guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { return nil } 107 | self.init(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue) 108 | } 109 | 110 | public convenience init?(queueQoS: DispatchQoS = .default, targetQueue: DispatchQueue? = nil) { 111 | var zeroAddress = sockaddr() 112 | zeroAddress.sa_len = UInt8(MemoryLayout.size) 113 | zeroAddress.sa_family = sa_family_t(AF_INET) 114 | 115 | guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { return nil } 116 | 117 | self.init(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue) 118 | } 119 | 120 | deinit { 121 | stopNotifier() 122 | } 123 | } 124 | 125 | public extension Reachability { 126 | 127 | // MARK: - *** Notifier methods *** 128 | func startNotifier() throws { 129 | guard !notifierRunning else { return } 130 | 131 | let callback: SCNetworkReachabilityCallBack = { (reachability, flags, info) in 132 | guard let info = info else { return } 133 | 134 | let reachability = Unmanaged.fromOpaque(info).takeUnretainedValue() 135 | reachability.flags = flags 136 | } 137 | 138 | var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) 139 | context.info = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()) 140 | if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context) { 141 | stopNotifier() 142 | throw ReachabilityError.UnableToSetCallback 143 | } 144 | 145 | if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) { 146 | stopNotifier() 147 | throw ReachabilityError.UnableToSetDispatchQueue 148 | } 149 | 150 | // Perform an initial check 151 | try setReachabilityFlags() 152 | 153 | notifierRunning = true 154 | } 155 | 156 | func stopNotifier() { 157 | defer { notifierRunning = false } 158 | 159 | SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil) 160 | SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil) 161 | } 162 | 163 | // MARK: - *** Connection test methods *** 164 | @available(*, deprecated, message: "Please use `connection != .none`") 165 | var isReachable: Bool { 166 | return connection != .none 167 | } 168 | 169 | @available(*, deprecated, message: "Please use `connection == .cellular`") 170 | var isReachableViaWWAN: Bool { 171 | // Check we're not on the simulator, we're REACHABLE and check we're on WWAN 172 | return connection == .cellular 173 | } 174 | 175 | @available(*, deprecated, message: "Please use `connection == .wifi`") 176 | var isReachableViaWiFi: Bool { 177 | return connection == .wifi 178 | } 179 | 180 | var description: String { 181 | guard let flags = flags else { return "unavailable flags" } 182 | let W = isRunningOnDevice ? (flags.isOnWWANFlagSet ? "W" : "-") : "X" 183 | let R = flags.isReachableFlagSet ? "R" : "-" 184 | let c = flags.isConnectionRequiredFlagSet ? "c" : "-" 185 | let t = flags.isTransientConnectionFlagSet ? "t" : "-" 186 | let i = flags.isInterventionRequiredFlagSet ? "i" : "-" 187 | let C = flags.isConnectionOnTrafficFlagSet ? "C" : "-" 188 | let D = flags.isConnectionOnDemandFlagSet ? "D" : "-" 189 | let l = flags.isLocalAddressFlagSet ? "l" : "-" 190 | let d = flags.isDirectFlagSet ? "d" : "-" 191 | 192 | return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)" 193 | } 194 | } 195 | 196 | fileprivate extension Reachability { 197 | 198 | func setReachabilityFlags() throws { 199 | try reachabilitySerialQueue.sync { [unowned self] in 200 | var flags = SCNetworkReachabilityFlags() 201 | if !SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags) { 202 | self.stopNotifier() 203 | throw ReachabilityError.UnableToGetInitialFlags 204 | } 205 | 206 | self.flags = flags 207 | } 208 | } 209 | 210 | func reachabilityChanged() { 211 | let block = connection != .none ? whenReachable : whenUnreachable 212 | 213 | DispatchQueue.main.async { [weak self] in 214 | guard let self = self else { return } 215 | block?(self) 216 | self.notificationCenter.post(name: .reachabilityChanged, object: self) 217 | } 218 | } 219 | } 220 | 221 | extension SCNetworkReachabilityFlags { 222 | 223 | typealias Connection = Reachability.Connection 224 | 225 | var connection: Connection { 226 | guard isReachableFlagSet else { return .none } 227 | 228 | // If we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi 229 | #if targetEnvironment(simulator) 230 | return .wifi 231 | #else 232 | var connection = Connection.none 233 | 234 | if !isConnectionRequiredFlagSet { 235 | connection = .wifi 236 | } 237 | 238 | if isConnectionOnTrafficOrDemandFlagSet { 239 | if !isInterventionRequiredFlagSet { 240 | connection = .wifi 241 | } 242 | } 243 | 244 | if isOnWWANFlagSet { 245 | connection = .cellular 246 | } 247 | 248 | return connection 249 | #endif 250 | } 251 | 252 | var isOnWWANFlagSet: Bool { 253 | #if os(iOS) 254 | return contains(.isWWAN) 255 | #else 256 | return false 257 | #endif 258 | } 259 | var isReachableFlagSet: Bool { 260 | return contains(.reachable) 261 | } 262 | var isConnectionRequiredFlagSet: Bool { 263 | return contains(.connectionRequired) 264 | } 265 | var isInterventionRequiredFlagSet: Bool { 266 | return contains(.interventionRequired) 267 | } 268 | var isConnectionOnTrafficFlagSet: Bool { 269 | return contains(.connectionOnTraffic) 270 | } 271 | var isConnectionOnDemandFlagSet: Bool { 272 | return contains(.connectionOnDemand) 273 | } 274 | var isConnectionOnTrafficOrDemandFlagSet: Bool { 275 | return !intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty 276 | } 277 | var isTransientConnectionFlagSet: Bool { 278 | return contains(.transientConnection) 279 | } 280 | var isLocalAddressFlagSet: Bool { 281 | return contains(.isLocalAddress) 282 | } 283 | var isDirectFlagSet: Bool { 284 | return contains(.isDirect) 285 | } 286 | var isConnectionRequiredAndTransientFlagSet: Bool { 287 | return intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection] 288 | } 289 | } 290 | 291 | -------------------------------------------------------------------------------- /Networking/Networking/RequestConfigurator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RequestConfigurator.swift 3 | // Networking 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | 12 | public struct RequestConfigurator { 13 | 14 | // MARK: - Variables 15 | 16 | // Parameters that will be passed into url 17 | // as query string 18 | public var parameters: Parameters? 19 | 20 | // Additional path will be added to source url 21 | public var path: String? 22 | 23 | // The HTTP Method of the request 24 | // Ex: .get, .post 25 | public var httpMethod: HTTPMethod? 26 | 27 | // MARK: - Initializer 28 | public init(path: String = "", parameters: Parameters? = [:], httpMethod: HTTPMethod? = .get) { 29 | self.path = path 30 | self.parameters = parameters 31 | self.httpMethod = httpMethod 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Networking/NetworkingTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Networking/NetworkingTests/NetworkingTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkingTests.swift 3 | // NetworkingTests 4 | // 5 | // Created by Oguz Parlak on 27.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Networking 11 | 12 | class NetworkingTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '10.0' 3 | use_frameworks! 4 | 5 | workspace 'MVVM-C-App-Core-Networking' 6 | 7 | project 'MVVM-C-App-Core-Networking' 8 | project 'Networking/Networking' 9 | 10 | def alamofire 11 | pod 'Alamofire', :git => 'https://github.com/Alamofire/Alamofire.git', :branch => 'alamofire5' 12 | end 13 | 14 | def uiPods 15 | pod 'Kingfisher', '~> 5.0' 16 | end 17 | 18 | target 'MVVM-C-App-Core-Networking' do 19 | use_frameworks! 20 | project 'MVVM-C-App-Core-Networking' 21 | alamofire 22 | uiPods 23 | end 24 | 25 | target 'Networking' do 26 | use_frameworks! 27 | project 'Networking/Networking' 28 | alamofire 29 | end 30 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (5.0.0.beta.1) 3 | - Kingfisher (5.4.0) 4 | 5 | DEPENDENCIES: 6 | - Alamofire (from `https://github.com/Alamofire/Alamofire.git`, branch `alamofire5`) 7 | - Kingfisher (~> 5.0) 8 | 9 | SPEC REPOS: 10 | https://github.com/cocoapods/specs.git: 11 | - Kingfisher 12 | 13 | EXTERNAL SOURCES: 14 | Alamofire: 15 | :branch: alamofire5 16 | :git: https://github.com/Alamofire/Alamofire.git 17 | 18 | CHECKOUT OPTIONS: 19 | Alamofire: 20 | :commit: 2c99a6691dac40f03ef9f9e89aaf2eb751843393 21 | :git: https://github.com/Alamofire/Alamofire.git 22 | 23 | SPEC CHECKSUMS: 24 | Alamofire: 2ef6d6c984c5d21c366e9b41a9ae7dfee2b67a44 25 | Kingfisher: 9c8f2cc6710334e06f32ba2b45e77707d5e2f0c9 26 | 27 | PODFILE CHECKSUM: fbf223c56a6418b3a8a18103eaa047842cce0484 28 | 29 | COCOAPODS: 1.7.4 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MVVM-C-Networking App Core 2 | 3 | [![IDE](https://img.shields.io/badge/Xcode-10-blue.svg)](https://developer.apple.com/xcode/) 4 | [![Language](https://img.shields.io/badge/swift-4-orange.svg)](https://swift.org) 5 | [![Platform](https://img.shields.io/badge/iOS-12-green.svg)](https://developer.apple.com/ios/) 6 | 7 | A lightweight, easy and ready to use, highly extensible core module for you to integrate into your project. This project aims to create clean, extensible and weakly coupled architecture for everybody to use. 8 | 9 | # Demo 10 | ![Demo](https://user-images.githubusercontent.com/14904310/60686332-c222bd00-9eb0-11e9-9363-541a51661b4b.GIF) 11 | 12 | # Installation Guide 13 | `git clone https://github.com/oguzparlak/MVVM-C-Networking-AppCore.git 14 | ` 15 | 16 | `cd MVVM-C-Networking-AppCore 17 | ` 18 | 19 | `pod install 20 | ` 21 | 22 | `open MVVM-C-App-Core-Networking.xcworkspace 23 | ` 24 | 25 | # Techstack 26 | - MVVM 27 | - Coordinator Pattern 28 | - Repository Pattern 29 | - Alamofire 30 | 31 | # Modules 32 | ## Core 33 | Core module provides you: 34 | - Navigation (via Coordinator) 35 | - Data Management 36 | - Repository 37 | - Caching 38 | - UI Componenets (Not implemented in this project) 39 | 40 | ## Networking 41 | Networking module does does nothing but API Request. It manages your network requests and routes with specified parameters, paths, http methods. 42 | 43 | # Code Samples 44 | This feature sample consumes TMDB API. It displays the trending TV Shows with Pagination. This feature will guide you how to apply core modules into your feature module. 45 | 46 | ## Coordinator 47 | Define your coordinator like this. In start method initialize your `View`. You may want to coordinate to another scene. This project is a SingleViewApplication. So you may want to checkout [this](https://github.com/oguzparlak/CoordinatorExperiment) project to see how routing is made between Coordinators. 48 | 49 | ```swift 50 | import Foundation 51 | import Core 52 | 53 | class TVShowListingCoordinator: ConcreteCoordinator { 54 | 55 | override func start() { 56 | let listingView = TVShowListingView.instantiate() 57 | listingView.coordinator = self 58 | listingView.title = "Backlight" 59 | listingView.tabBarItem = UITabBarItem(title: "Popular", image: UIImage(named: "ic_popular_disabled"), selectedImage: UIImage(named: "ic_popular")) 60 | navigationController.pushViewController(listingView, animated: true) 61 | navigationController.configureTheme() 62 | } 63 | 64 | func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { 65 | if childCoordinatorShouldNotBeDeleted(navigationController: navigationController) { return } 66 | } 67 | 68 | } 69 | ``` 70 | 71 | ## View 72 | Define your Views as usual. Keep an instance of your `Coordinator` and `ViewModel` 73 | 74 | ```swift 75 | import UIKit 76 | import Core 77 | 78 | class TVShowListingView: UIViewController, Storyboarded { 79 | 80 | // MARK: - UI Elements 81 | 82 | @IBOutlet weak var tableView: UITableView! 83 | 84 | // MARK: - Public Variables 85 | 86 | weak var coordinator: TVShowListingCoordinator? 87 | var tvShowViewModel: TVShowViewModel? 88 | 89 | // MARK: - Methods 90 | func initTableView() { 91 | tableView.delegate = self 92 | tableView.dataSource = self 93 | tableView.prefetchDataSource = self 94 | tableView.rowHeight = UITableView.automaticDimension 95 | tableView.backgroundColor = .black 96 | tableView.register(UINib(nibName: "MovieListingCell", bundle: nil), forCellReuseIdentifier: "MovieListingCell") 97 | } 98 | 99 | } 100 | 101 | // MARK: - Lifecycle 102 | extension TVShowListingView { 103 | 104 | override func viewDidLoad() { 105 | super.viewDidLoad() 106 | // Do any additional setup after loading the view. 107 | tvShowViewModel = TVShowViewModel(tvShowInteractor: self) 108 | initTableView() 109 | } 110 | 111 | } 112 | ``` 113 | 114 | ## ViewModel 115 | Your ViewModel manages the data and view. Keep an instance of `Model`, `Repository` and `Interactor` here. 116 | When Network request comes through fetch the remote data via Repository and update the model. Finally, you can update your view. 117 | 118 | ```swift 119 | import Foundation 120 | import Core 121 | import Networking 122 | 123 | class TVShowViewModel { 124 | 125 | var tvShowContainer: TVShowContainer? { 126 | didSet { 127 | // Update UI 128 | updateCellViewModels() 129 | tvShowInteractor.shouldUpdateTableView() 130 | } 131 | } 132 | 133 | var tvShowCellViewModels: [TVShowCellViewModel] = [] 134 | 135 | private let tvShowRepository: TVShowRepository 136 | private let tvShowInteractor: TVShowInteractor 137 | 138 | init(tvShowRepository: TVShowRepository = TVShowRepository(requestConfigurator: RequestConfigurator(path: TVShowEndPoint.trendingTvShows(timeWindow: "week").provideUrl(), parameters: [Constants.Parameters.api_key : Constants.tmdbApiKey])), tvShowInteractor: TVShowInteractor) { 139 | self.tvShowRepository = tvShowRepository 140 | self.tvShowInteractor = tvShowInteractor 141 | fetchTVShows() 142 | } 143 | 144 | func fetchTVShows(shouldApplyPagination: Bool = false) { 145 | if shouldApplyPagination { tvShowRepository.incrementPage() } 146 | self.tvShowRepository.getRemoteDataSource(responseCallback: { [weak self] result in 147 | switch result { 148 | case .success(let tvShows): 149 | self?.tvShowContainer = tvShows 150 | case .error(let error): 151 | print(error) 152 | } 153 | }) 154 | } 155 | 156 | func updateCellViewModels() { 157 | let tvShows = tvShowContainer?.results ?? [] 158 | for tvShow in tvShows { 159 | tvShowCellViewModels.append(TVShowCellViewModel(tvShow: tvShow)) 160 | } 161 | } 162 | 163 | } 164 | ``` 165 | 166 | ## Repository 167 | Repository is a gateway between your feature layer and network layer. It either fetches the data from remote or cache. 168 | Define your Repository like this: 169 | 170 | ```swift 171 | import Foundation 172 | import Networking 173 | import Core 174 | 175 | class TVShowRepository: Repository { 176 | 177 | typealias T = TVShowContainer? 178 | 179 | private var requestConfigurator: RequestConfigurator 180 | 181 | private var dataManager: TVShowDataManager? 182 | 183 | private var currentPage: Int = 1 { 184 | didSet { 185 | requestConfigurator.parameters = [ 186 | "page" : String(currentPage), 187 | Constants.Parameters.api_key: Constants.tmdbApiKey] 188 | } 189 | } 190 | 191 | func incrementPage() { 192 | currentPage += 1 193 | } 194 | 195 | public init(requestConfigurator: RequestConfigurator, dataManager: TVShowDataManager? = TVShowDataManager(dataNotifier: DataNotifier(dataCallback: { (container) in 196 | 197 | }, errorCallback: { (error) in 198 | 199 | }))) { 200 | self.dataManager = dataManager 201 | self.requestConfigurator = requestConfigurator 202 | } 203 | 204 | func getLocalDataSource() -> TVShowContainer? { 205 | return dataManager?.loadAllTVShows() 206 | } 207 | 208 | func getRemoteDataSource(responseCallback: @escaping (Result) -> Void) { 209 | ApiClient.request(ApiRouter(requestConfigurator: requestConfigurator), completion: responseCallback) 210 | } 211 | 212 | } 213 | ``` 214 | 215 | ## Networking 216 | Define your endpoints for specific feature. 217 | 218 | ```swift 219 | import Foundation 220 | import Networking 221 | 222 | /// Models the TVShowEndPoint 223 | enum TVShowEndPoint : EndpointProvider { 224 | 225 | // Gathers popular tv shows weekly or daily 226 | case trendingTvShows(timeWindow: String) 227 | case image(width: String, posterPath: String) 228 | 229 | // MARK: - EndPointProvider conforming methods 230 | 231 | func provideUrl() -> String { 232 | 233 | switch self { 234 | case .trendingTvShows(let timeWindow): 235 | return "trending/tv/\(timeWindow)" 236 | case .image(let width, let posterPath): 237 | return "https://image.tmdb.org/t/p/w\(width)/\(posterPath)" 238 | } 239 | } 240 | 241 | // MARK: - Private methods 242 | 243 | private func parameters(for page: Int) -> [String : String] { 244 | return [ 245 | "page" : String(page) 246 | ] 247 | } 248 | } 249 | ``` 250 | 251 | # Acknowledgement 252 | Thank you [Paul Hudson](https://www.hackingwithswift.com/about) for clarifying the `Coordinator` pattern. And also special thanks to [Ali Can Batur](https://github.com/alicanbatur) for code review. 253 | -------------------------------------------------------------------------------- /Root/RootController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RootController.swift 3 | // MVVM-C-App-Core-Networking 4 | // 5 | // Created by Oguz Parlak on 30.06.2019. 6 | // Copyright © 2019 Oguz Parlak. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Core 11 | 12 | class RootController: UITabBarController { 13 | 14 | let tvShowListingCoordinator = TVShowListingCoordinator(navigationController: UINavigationController()) 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | // MARK: - Customize UI 20 | if #available(iOS 11.0, *) { 21 | tabBar.barTintColor = .black 22 | tabBar.tintColor = UIColor(named: "color_theme") 23 | } 24 | UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.font: UIFont(name: "Futura", size: 11) as Any], for: .normal) 25 | UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.font: UIFont(name: "Futura", size: 11) as Any], for: .selected) 26 | 27 | // MARK: - Start Coordinators 28 | tvShowListingCoordinator.start() 29 | 30 | // MARK: - Specify ViewControllers 31 | viewControllers = [tvShowListingCoordinator.navigationController] 32 | 33 | } 34 | 35 | } 36 | --------------------------------------------------------------------------------