├── MVVM-Inception.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved └── xcuserdata │ └── shubhamsingh.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── MVVM-Inception ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ └── LaunchScreen.storyboard ├── Code │ ├── Controllers │ │ ├── AppDelegate.swift │ │ ├── Box.swift │ │ └── SceneDelegate.swift │ ├── Models │ │ └── Post.swift │ ├── Modules │ │ └── Home │ │ │ ├── Base.lproj │ │ │ └── Main.storyboard │ │ │ ├── HomeViewController.swift │ │ │ └── ViewModels │ │ │ └── PostListViewModel.swift │ └── Services │ │ ├── CoreDataManager.swift │ │ ├── DataManager.swift │ │ └── NetworkManager.swift ├── Info.plist └── MVVM.png └── README.md /MVVM-Inception.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | F31C08C225C2A8610036F57F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F31C08C125C2A8610036F57F /* AppDelegate.swift */; }; 11 | F31C08C425C2A8610036F57F /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F31C08C325C2A8610036F57F /* SceneDelegate.swift */; }; 12 | F31C08C625C2A8610036F57F /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F31C08C525C2A8610036F57F /* HomeViewController.swift */; }; 13 | F31C08C925C2A8610036F57F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F31C08C725C2A8610036F57F /* Main.storyboard */; }; 14 | F31C08CB25C2A8630036F57F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F31C08CA25C2A8630036F57F /* Assets.xcassets */; }; 15 | F31C08CE25C2A8630036F57F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F31C08CC25C2A8630036F57F /* LaunchScreen.storyboard */; }; 16 | F31C08DE25C2A9390036F57F /* DataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F31C08DD25C2A9390036F57F /* DataManager.swift */; }; 17 | F31C08E125C2A94E0036F57F /* CoreDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F31C08E025C2A94E0036F57F /* CoreDataManager.swift */; }; 18 | F31C08E425C2A95C0036F57F /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F31C08E325C2A95C0036F57F /* NetworkManager.swift */; }; 19 | F31C08E825C2AA710036F57F /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = F31C08E725C2AA710036F57F /* Alamofire */; }; 20 | F3AF86B125C2AC71004D2169 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3AF86B025C2AC71004D2169 /* Post.swift */; }; 21 | F3AF86B525C2BD99004D2169 /* PostListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3AF86B425C2BD99004D2169 /* PostListViewModel.swift */; }; 22 | F3AF86B925C2BDEA004D2169 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3AF86B825C2BDEA004D2169 /* Box.swift */; }; 23 | F3AF86BC25C2E992004D2169 /* MVVM.png in Resources */ = {isa = PBXBuildFile; fileRef = F3AF86BB25C2E992004D2169 /* MVVM.png */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | F31C08BE25C2A8610036F57F /* MVVM-Inception.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MVVM-Inception.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | F31C08C125C2A8610036F57F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 29 | F31C08C325C2A8610036F57F /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 30 | F31C08C525C2A8610036F57F /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = ""; }; 31 | F31C08C825C2A8610036F57F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 32 | F31C08CA25C2A8630036F57F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 33 | F31C08CD25C2A8630036F57F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 34 | F31C08CF25C2A8630036F57F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | F31C08DD25C2A9390036F57F /* DataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataManager.swift; sourceTree = ""; }; 36 | F31C08E025C2A94E0036F57F /* CoreDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataManager.swift; sourceTree = ""; }; 37 | F31C08E325C2A95C0036F57F /* NetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = ""; }; 38 | F3AF86B025C2AC71004D2169 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = ""; }; 39 | F3AF86B425C2BD99004D2169 /* PostListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostListViewModel.swift; sourceTree = ""; }; 40 | F3AF86B825C2BDEA004D2169 /* Box.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = ""; }; 41 | F3AF86BB25C2E992004D2169 /* MVVM.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = MVVM.png; sourceTree = ""; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | F31C08BB25C2A8610036F57F /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | F31C08E825C2AA710036F57F /* Alamofire in Frameworks */, 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXFrameworksBuildPhase section */ 54 | 55 | /* Begin PBXGroup section */ 56 | F31C08B525C2A8610036F57F = { 57 | isa = PBXGroup; 58 | children = ( 59 | F31C08C025C2A8610036F57F /* MVVM-Inception */, 60 | F31C08BF25C2A8610036F57F /* Products */, 61 | ); 62 | sourceTree = ""; 63 | }; 64 | F31C08BF25C2A8610036F57F /* Products */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | F31C08BE25C2A8610036F57F /* MVVM-Inception.app */, 68 | ); 69 | name = Products; 70 | sourceTree = ""; 71 | }; 72 | F31C08C025C2A8610036F57F /* MVVM-Inception */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | F31C08D625C2A86A0036F57F /* Code */, 76 | F31C08CA25C2A8630036F57F /* Assets.xcassets */, 77 | F3AF86BB25C2E992004D2169 /* MVVM.png */, 78 | F31C08CC25C2A8630036F57F /* LaunchScreen.storyboard */, 79 | F31C08CF25C2A8630036F57F /* Info.plist */, 80 | ); 81 | path = "MVVM-Inception"; 82 | sourceTree = ""; 83 | }; 84 | F31C08D625C2A86A0036F57F /* Code */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | F31C08D725C2A86F0036F57F /* Controllers */, 88 | F3AF86AE25C2AC38004D2169 /* Models */, 89 | F31C08D925C2A8CA0036F57F /* Modules */, 90 | F31C08DC25C2A90F0036F57F /* Services */, 91 | ); 92 | path = Code; 93 | sourceTree = ""; 94 | }; 95 | F31C08D725C2A86F0036F57F /* Controllers */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | F31C08C125C2A8610036F57F /* AppDelegate.swift */, 99 | F31C08C325C2A8610036F57F /* SceneDelegate.swift */, 100 | F3AF86B825C2BDEA004D2169 /* Box.swift */, 101 | ); 102 | path = Controllers; 103 | sourceTree = ""; 104 | }; 105 | F31C08D925C2A8CA0036F57F /* Modules */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | F31C08DA25C2A8D10036F57F /* Home */, 109 | ); 110 | path = Modules; 111 | sourceTree = ""; 112 | }; 113 | F31C08DA25C2A8D10036F57F /* Home */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | F3AF86B325C2BD88004D2169 /* ViewModels */, 117 | F31C08C525C2A8610036F57F /* HomeViewController.swift */, 118 | F31C08C725C2A8610036F57F /* Main.storyboard */, 119 | ); 120 | path = Home; 121 | sourceTree = ""; 122 | }; 123 | F31C08DC25C2A90F0036F57F /* Services */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | F31C08DD25C2A9390036F57F /* DataManager.swift */, 127 | F31C08E025C2A94E0036F57F /* CoreDataManager.swift */, 128 | F31C08E325C2A95C0036F57F /* NetworkManager.swift */, 129 | ); 130 | path = Services; 131 | sourceTree = ""; 132 | }; 133 | F3AF86AE25C2AC38004D2169 /* Models */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | F3AF86B025C2AC71004D2169 /* Post.swift */, 137 | ); 138 | path = Models; 139 | sourceTree = ""; 140 | }; 141 | F3AF86B325C2BD88004D2169 /* ViewModels */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | F3AF86B425C2BD99004D2169 /* PostListViewModel.swift */, 145 | ); 146 | path = ViewModels; 147 | sourceTree = ""; 148 | }; 149 | /* End PBXGroup section */ 150 | 151 | /* Begin PBXNativeTarget section */ 152 | F31C08BD25C2A8610036F57F /* MVVM-Inception */ = { 153 | isa = PBXNativeTarget; 154 | buildConfigurationList = F31C08D225C2A8630036F57F /* Build configuration list for PBXNativeTarget "MVVM-Inception" */; 155 | buildPhases = ( 156 | F31C08BA25C2A8610036F57F /* Sources */, 157 | F31C08BB25C2A8610036F57F /* Frameworks */, 158 | F31C08BC25C2A8610036F57F /* Resources */, 159 | ); 160 | buildRules = ( 161 | ); 162 | dependencies = ( 163 | ); 164 | name = "MVVM-Inception"; 165 | packageProductDependencies = ( 166 | F31C08E725C2AA710036F57F /* Alamofire */, 167 | ); 168 | productName = "MVVM-Inception"; 169 | productReference = F31C08BE25C2A8610036F57F /* MVVM-Inception.app */; 170 | productType = "com.apple.product-type.application"; 171 | }; 172 | /* End PBXNativeTarget section */ 173 | 174 | /* Begin PBXProject section */ 175 | F31C08B625C2A8610036F57F /* Project object */ = { 176 | isa = PBXProject; 177 | attributes = { 178 | LastSwiftUpdateCheck = 1230; 179 | LastUpgradeCheck = 1230; 180 | TargetAttributes = { 181 | F31C08BD25C2A8610036F57F = { 182 | CreatedOnToolsVersion = 12.3; 183 | }; 184 | }; 185 | }; 186 | buildConfigurationList = F31C08B925C2A8610036F57F /* Build configuration list for PBXProject "MVVM-Inception" */; 187 | compatibilityVersion = "Xcode 9.3"; 188 | developmentRegion = en; 189 | hasScannedForEncodings = 0; 190 | knownRegions = ( 191 | en, 192 | Base, 193 | ); 194 | mainGroup = F31C08B525C2A8610036F57F; 195 | packageReferences = ( 196 | F31C08E625C2AA710036F57F /* XCRemoteSwiftPackageReference "Alamofire" */, 197 | ); 198 | productRefGroup = F31C08BF25C2A8610036F57F /* Products */; 199 | projectDirPath = ""; 200 | projectRoot = ""; 201 | targets = ( 202 | F31C08BD25C2A8610036F57F /* MVVM-Inception */, 203 | ); 204 | }; 205 | /* End PBXProject section */ 206 | 207 | /* Begin PBXResourcesBuildPhase section */ 208 | F31C08BC25C2A8610036F57F /* Resources */ = { 209 | isa = PBXResourcesBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | F31C08CE25C2A8630036F57F /* LaunchScreen.storyboard in Resources */, 213 | F3AF86BC25C2E992004D2169 /* MVVM.png in Resources */, 214 | F31C08CB25C2A8630036F57F /* Assets.xcassets in Resources */, 215 | F31C08C925C2A8610036F57F /* Main.storyboard in Resources */, 216 | ); 217 | runOnlyForDeploymentPostprocessing = 0; 218 | }; 219 | /* End PBXResourcesBuildPhase section */ 220 | 221 | /* Begin PBXSourcesBuildPhase section */ 222 | F31C08BA25C2A8610036F57F /* Sources */ = { 223 | isa = PBXSourcesBuildPhase; 224 | buildActionMask = 2147483647; 225 | files = ( 226 | F3AF86B925C2BDEA004D2169 /* Box.swift in Sources */, 227 | F3AF86B525C2BD99004D2169 /* PostListViewModel.swift in Sources */, 228 | F31C08E425C2A95C0036F57F /* NetworkManager.swift in Sources */, 229 | F31C08C625C2A8610036F57F /* HomeViewController.swift in Sources */, 230 | F31C08DE25C2A9390036F57F /* DataManager.swift in Sources */, 231 | F31C08C225C2A8610036F57F /* AppDelegate.swift in Sources */, 232 | F31C08E125C2A94E0036F57F /* CoreDataManager.swift in Sources */, 233 | F3AF86B125C2AC71004D2169 /* Post.swift in Sources */, 234 | F31C08C425C2A8610036F57F /* SceneDelegate.swift in Sources */, 235 | ); 236 | runOnlyForDeploymentPostprocessing = 0; 237 | }; 238 | /* End PBXSourcesBuildPhase section */ 239 | 240 | /* Begin PBXVariantGroup section */ 241 | F31C08C725C2A8610036F57F /* Main.storyboard */ = { 242 | isa = PBXVariantGroup; 243 | children = ( 244 | F31C08C825C2A8610036F57F /* Base */, 245 | ); 246 | name = Main.storyboard; 247 | sourceTree = ""; 248 | }; 249 | F31C08CC25C2A8630036F57F /* LaunchScreen.storyboard */ = { 250 | isa = PBXVariantGroup; 251 | children = ( 252 | F31C08CD25C2A8630036F57F /* Base */, 253 | ); 254 | name = LaunchScreen.storyboard; 255 | sourceTree = ""; 256 | }; 257 | /* End PBXVariantGroup section */ 258 | 259 | /* Begin XCBuildConfiguration section */ 260 | F31C08D025C2A8630036F57F /* Debug */ = { 261 | isa = XCBuildConfiguration; 262 | buildSettings = { 263 | ALWAYS_SEARCH_USER_PATHS = NO; 264 | CLANG_ANALYZER_NONNULL = YES; 265 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 266 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 267 | CLANG_CXX_LIBRARY = "libc++"; 268 | CLANG_ENABLE_MODULES = YES; 269 | CLANG_ENABLE_OBJC_ARC = YES; 270 | CLANG_ENABLE_OBJC_WEAK = YES; 271 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 272 | CLANG_WARN_BOOL_CONVERSION = YES; 273 | CLANG_WARN_COMMA = YES; 274 | CLANG_WARN_CONSTANT_CONVERSION = YES; 275 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 277 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 278 | CLANG_WARN_EMPTY_BODY = YES; 279 | CLANG_WARN_ENUM_CONVERSION = YES; 280 | CLANG_WARN_INFINITE_RECURSION = YES; 281 | CLANG_WARN_INT_CONVERSION = YES; 282 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 283 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 284 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 286 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 287 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 288 | CLANG_WARN_STRICT_PROTOTYPES = YES; 289 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 290 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 291 | CLANG_WARN_UNREACHABLE_CODE = YES; 292 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 293 | COPY_PHASE_STRIP = NO; 294 | DEBUG_INFORMATION_FORMAT = dwarf; 295 | ENABLE_STRICT_OBJC_MSGSEND = YES; 296 | ENABLE_TESTABILITY = YES; 297 | GCC_C_LANGUAGE_STANDARD = gnu11; 298 | GCC_DYNAMIC_NO_PIC = NO; 299 | GCC_NO_COMMON_BLOCKS = YES; 300 | GCC_OPTIMIZATION_LEVEL = 0; 301 | GCC_PREPROCESSOR_DEFINITIONS = ( 302 | "DEBUG=1", 303 | "$(inherited)", 304 | ); 305 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 306 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 307 | GCC_WARN_UNDECLARED_SELECTOR = YES; 308 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 309 | GCC_WARN_UNUSED_FUNCTION = YES; 310 | GCC_WARN_UNUSED_VARIABLE = YES; 311 | IPHONEOS_DEPLOYMENT_TARGET = 14.3; 312 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 313 | MTL_FAST_MATH = YES; 314 | ONLY_ACTIVE_ARCH = YES; 315 | SDKROOT = iphoneos; 316 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 317 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 318 | }; 319 | name = Debug; 320 | }; 321 | F31C08D125C2A8630036F57F /* Release */ = { 322 | isa = XCBuildConfiguration; 323 | buildSettings = { 324 | ALWAYS_SEARCH_USER_PATHS = NO; 325 | CLANG_ANALYZER_NONNULL = YES; 326 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 327 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 328 | CLANG_CXX_LIBRARY = "libc++"; 329 | CLANG_ENABLE_MODULES = YES; 330 | CLANG_ENABLE_OBJC_ARC = YES; 331 | CLANG_ENABLE_OBJC_WEAK = YES; 332 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 333 | CLANG_WARN_BOOL_CONVERSION = YES; 334 | CLANG_WARN_COMMA = YES; 335 | CLANG_WARN_CONSTANT_CONVERSION = YES; 336 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 337 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 338 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 339 | CLANG_WARN_EMPTY_BODY = YES; 340 | CLANG_WARN_ENUM_CONVERSION = YES; 341 | CLANG_WARN_INFINITE_RECURSION = YES; 342 | CLANG_WARN_INT_CONVERSION = YES; 343 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 344 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 345 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 346 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 347 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 348 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 349 | CLANG_WARN_STRICT_PROTOTYPES = YES; 350 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 351 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 352 | CLANG_WARN_UNREACHABLE_CODE = YES; 353 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 354 | COPY_PHASE_STRIP = NO; 355 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 356 | ENABLE_NS_ASSERTIONS = NO; 357 | ENABLE_STRICT_OBJC_MSGSEND = YES; 358 | GCC_C_LANGUAGE_STANDARD = gnu11; 359 | GCC_NO_COMMON_BLOCKS = YES; 360 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 361 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 362 | GCC_WARN_UNDECLARED_SELECTOR = YES; 363 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 364 | GCC_WARN_UNUSED_FUNCTION = YES; 365 | GCC_WARN_UNUSED_VARIABLE = YES; 366 | IPHONEOS_DEPLOYMENT_TARGET = 14.3; 367 | MTL_ENABLE_DEBUG_INFO = NO; 368 | MTL_FAST_MATH = YES; 369 | SDKROOT = iphoneos; 370 | SWIFT_COMPILATION_MODE = wholemodule; 371 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 372 | VALIDATE_PRODUCT = YES; 373 | }; 374 | name = Release; 375 | }; 376 | F31C08D325C2A8630036F57F /* Debug */ = { 377 | isa = XCBuildConfiguration; 378 | buildSettings = { 379 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 380 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 381 | CODE_SIGN_STYLE = Automatic; 382 | DEVELOPMENT_TEAM = VXZ7XFH447; 383 | INFOPLIST_FILE = "MVVM-Inception/Info.plist"; 384 | LD_RUNPATH_SEARCH_PATHS = ( 385 | "$(inherited)", 386 | "@executable_path/Frameworks", 387 | ); 388 | PRODUCT_BUNDLE_IDENTIFIER = "com.shubham-iosdev.MVVM-Inception"; 389 | PRODUCT_NAME = "$(TARGET_NAME)"; 390 | SWIFT_VERSION = 5.0; 391 | TARGETED_DEVICE_FAMILY = "1,2"; 392 | }; 393 | name = Debug; 394 | }; 395 | F31C08D425C2A8630036F57F /* Release */ = { 396 | isa = XCBuildConfiguration; 397 | buildSettings = { 398 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 399 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 400 | CODE_SIGN_STYLE = Automatic; 401 | DEVELOPMENT_TEAM = VXZ7XFH447; 402 | INFOPLIST_FILE = "MVVM-Inception/Info.plist"; 403 | LD_RUNPATH_SEARCH_PATHS = ( 404 | "$(inherited)", 405 | "@executable_path/Frameworks", 406 | ); 407 | PRODUCT_BUNDLE_IDENTIFIER = "com.shubham-iosdev.MVVM-Inception"; 408 | PRODUCT_NAME = "$(TARGET_NAME)"; 409 | SWIFT_VERSION = 5.0; 410 | TARGETED_DEVICE_FAMILY = "1,2"; 411 | }; 412 | name = Release; 413 | }; 414 | /* End XCBuildConfiguration section */ 415 | 416 | /* Begin XCConfigurationList section */ 417 | F31C08B925C2A8610036F57F /* Build configuration list for PBXProject "MVVM-Inception" */ = { 418 | isa = XCConfigurationList; 419 | buildConfigurations = ( 420 | F31C08D025C2A8630036F57F /* Debug */, 421 | F31C08D125C2A8630036F57F /* Release */, 422 | ); 423 | defaultConfigurationIsVisible = 0; 424 | defaultConfigurationName = Release; 425 | }; 426 | F31C08D225C2A8630036F57F /* Build configuration list for PBXNativeTarget "MVVM-Inception" */ = { 427 | isa = XCConfigurationList; 428 | buildConfigurations = ( 429 | F31C08D325C2A8630036F57F /* Debug */, 430 | F31C08D425C2A8630036F57F /* Release */, 431 | ); 432 | defaultConfigurationIsVisible = 0; 433 | defaultConfigurationName = Release; 434 | }; 435 | /* End XCConfigurationList section */ 436 | 437 | /* Begin XCRemoteSwiftPackageReference section */ 438 | F31C08E625C2AA710036F57F /* XCRemoteSwiftPackageReference "Alamofire" */ = { 439 | isa = XCRemoteSwiftPackageReference; 440 | repositoryURL = "https://github.com/Alamofire/Alamofire"; 441 | requirement = { 442 | kind = upToNextMajorVersion; 443 | minimumVersion = 4.4.1; 444 | }; 445 | }; 446 | /* End XCRemoteSwiftPackageReference section */ 447 | 448 | /* Begin XCSwiftPackageProductDependency section */ 449 | F31C08E725C2AA710036F57F /* Alamofire */ = { 450 | isa = XCSwiftPackageProductDependency; 451 | package = F31C08E625C2AA710036F57F /* XCRemoteSwiftPackageReference "Alamofire" */; 452 | productName = Alamofire; 453 | }; 454 | /* End XCSwiftPackageProductDependency section */ 455 | }; 456 | rootObject = F31C08B625C2A8610036F57F /* Project object */; 457 | } 458 | -------------------------------------------------------------------------------- /MVVM-Inception.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MVVM-Inception.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MVVM-Inception.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Alamofire", 6 | "repositoryURL": "https://github.com/Alamofire/Alamofire", 7 | "state": { 8 | "branch": null, 9 | "revision": "747c8db8d57b68d5e35275f10c92d55f982adbd4", 10 | "version": "4.9.1" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /MVVM-Inception.xcodeproj/xcuserdata/shubhamsingh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /MVVM-Inception.xcodeproj/xcuserdata/shubhamsingh.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MVVM-Inception.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /MVVM-Inception/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /MVVM-Inception/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /MVVM-Inception/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /MVVM-Inception/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-Inception/Code/Controllers/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // MVVM-Inception 4 | // 5 | // Created by Shubham Singh on 28/01/21. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 14 | return true 15 | } 16 | 17 | // MARK: UISceneSession Lifecycle 18 | 19 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 20 | // Called when a new scene session is being created. 21 | // Use this method to select a configuration to create the new scene with. 22 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 23 | } 24 | 25 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 26 | // Called when the user discards a scene session. 27 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 28 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 29 | } 30 | 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /MVVM-Inception/Code/Controllers/Box.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Box.swift 3 | // MVVM-Inception 4 | // 5 | // Created by Shubham Singh on 28/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | class Box { 11 | typealias Listener = (T) -> () 12 | 13 | // MARK:- variables for the binder 14 | var value: T { 15 | didSet { 16 | listener?(value) 17 | } 18 | } 19 | 20 | var listener: Listener? 21 | 22 | // MARK:- initializers for the binder 23 | init(_ value: T) { 24 | self.value = value 25 | } 26 | 27 | // MARK:- functions for the binder 28 | func bind(listener: Listener?) { 29 | self.listener = listener 30 | listener?(value) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /MVVM-Inception/Code/Controllers/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // MVVM-Inception 4 | // 5 | // Created by Shubham Singh on 28/01/21. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | 15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 19 | guard let _ = (scene as? UIWindowScene) else { return } 20 | } 21 | 22 | func sceneDidDisconnect(_ scene: UIScene) { 23 | // Called as the scene is being released by the system. 24 | // This occurs shortly after the scene enters the background, or when its session is discarded. 25 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 27 | } 28 | 29 | func sceneDidBecomeActive(_ scene: UIScene) { 30 | // Called when the scene has moved from an inactive state to an active state. 31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 32 | } 33 | 34 | func sceneWillResignActive(_ scene: UIScene) { 35 | // Called when the scene will move from an active state to an inactive state. 36 | // This may occur due to temporary interruptions (ex. an incoming phone call). 37 | } 38 | 39 | func sceneWillEnterForeground(_ scene: UIScene) { 40 | // Called as the scene transitions from the background to the foreground. 41 | // Use this method to undo the changes made on entering the background. 42 | } 43 | 44 | func sceneDidEnterBackground(_ scene: UIScene) { 45 | // Called as the scene transitions from the foreground to the background. 46 | // Use this method to save data, release shared resources, and store enough scene-specific state information 47 | // to restore the scene back to its current state. 48 | } 49 | 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /MVVM-Inception/Code/Models/Post.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Post.swift 3 | // MVVM-Inception 4 | // 5 | // Created by Shubham Singh on 28/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Post: Codable { 11 | let userId: Int 12 | let id: Int 13 | let title: String 14 | let body: String 15 | } 16 | -------------------------------------------------------------------------------- /MVVM-Inception/Code/Modules/Home/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /MVVM-Inception/Code/Modules/Home/HomeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HomeViewController.swift 3 | // MVVM-Inception 4 | // 5 | // Created by Shubham Singh on 28/01/21. 6 | // 7 | 8 | import UIKit 9 | 10 | class HomeViewController: UIViewController { 11 | // MARK:- outlets 12 | @IBOutlet weak var tableView: UITableView! 13 | 14 | // MARK:- variables 15 | var postListViewModel: PostListViewModel! 16 | 17 | // MARK:- lifeCycle 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | self.postListViewModel = PostListViewModel() 21 | 22 | self.postListViewModel.posts.bind { 23 | if ($0 != nil) { 24 | self.tableView.reloadData() 25 | } 26 | } 27 | } 28 | } 29 | 30 | extension HomeViewController: UITableViewDataSource, UITableViewDelegate { 31 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 32 | guard let posts = self.postListViewModel.posts.value else { return 0 } 33 | return posts.count 34 | } 35 | 36 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 37 | guard let posts = self.postListViewModel.posts.value 38 | else { return UITableViewCell() } 39 | let cell = UITableViewCell() 40 | cell.textLabel?.text = posts[indexPath.row].title 41 | return cell 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /MVVM-Inception/Code/Modules/Home/ViewModels/PostListViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PostListViewModel.swift 3 | // MVVM-Inception 4 | // 5 | // Created by Shubham Singh on 28/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | struct PostListViewModel { 11 | 12 | // MARK:- variables 13 | let dataManager: DataManager 14 | 15 | var posts: Box<[Post]?> = Box(nil) 16 | 17 | var offset: Box = Box(0) 18 | var limit: Box = Box(30) 19 | 20 | // MARK:- initializer 21 | init(dataManager: DataManager = DataManager()) { 22 | self.dataManager = dataManager 23 | 24 | self.getPosts() 25 | } 26 | 27 | // MARK:- functions 28 | func getPosts() { 29 | self.dataManager.getPosts(offset: offset.value, limit: limit.value) { (posts, error) in 30 | guard let posts = posts else { return } 31 | self.posts.value = posts 32 | self.offset.value = posts.count 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /MVVM-Inception/Code/Services/CoreDataManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataManager.swift 3 | // MVVM-Inception 4 | // 5 | // Created by Shubham Singh on 28/01/21. 6 | // 7 | 8 | struct CoreDataManager { 9 | /// Implement Core Data get and save here 10 | } 11 | -------------------------------------------------------------------------------- /MVVM-Inception/Code/Services/DataManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataManager.swift 3 | // MVVM-Inception 4 | // 5 | // Created by Shubham Singh on 28/01/21. 6 | // 7 | 8 | import Foundation 9 | 10 | struct DataManager { 11 | 12 | // MARK:- variables 13 | let networkManager: NetworkManager 14 | 15 | // MARK:- initializers 16 | init(networkManager: NetworkManager = NetworkManager()) { 17 | self.networkManager = networkManager 18 | } 19 | 20 | // MARK:- functions 21 | func getPosts(offset: Int, limit: Int, onCompletion: @escaping([Post]?, Error?) -> ()) { 22 | let queries: [String : Any] = ["offset": offset, "limit": limit] 23 | 24 | self.networkManager.getPosts(queries: queries) { (res, error) in 25 | if (error == nil) { 26 | onCompletion(res, nil) 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /MVVM-Inception/Code/Services/NetworkManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkManager.swift 3 | // MVVM-Inception 4 | // 5 | // Created by Shubham Singh on 28/01/21. 6 | // 7 | 8 | import Foundation 9 | import Alamofire 10 | 11 | 12 | fileprivate enum APIs: URLRequestConvertible { 13 | 14 | case getAPI(path: String, data: [String: Any]) 15 | 16 | static let baseURL = URL(string: "https://jsonplaceholder.typicode.com/")! 17 | static let reachability = NetworkReachabilityManager()! 18 | 19 | // specifying the endpoints for each API 20 | var path: String { 21 | switch self { 22 | case .getAPI(let path, _): 23 | return path 24 | } 25 | } 26 | 27 | // specifying the methods for each API 28 | var method: HTTPMethod { 29 | switch self { 30 | default: 31 | return .get 32 | } 33 | } 34 | 35 | // If the API requires body or queryString encoding, it can be specified here 36 | var encoding : URLEncoding { 37 | switch self { 38 | case .getAPI(_, _): 39 | return .queryString 40 | } 41 | } 42 | 43 | func asURLRequest() throws -> URLRequest { 44 | var request = URLRequest(url: Self.baseURL.appendingPathComponent(path)) 45 | 46 | if (path.contains("auth/login")) { 47 | request = URLRequest(url: URL(string: path)!) 48 | } 49 | 50 | request.httpMethod = method.rawValue 51 | var parameters = Parameters() 52 | 53 | switch self { 54 | case .getAPI(_, let queries): 55 | for (k,v) in queries { 56 | parameters[k] = v 57 | } 58 | } 59 | 60 | // encoding the request with the encoding specified above if any 61 | request = try encoding.encode(request, with: parameters) 62 | request.timeoutInterval = 20 63 | return request 64 | } 65 | 66 | //MARK:- functions for calling the API's 67 | static func makeGetRequest(path: String, queries: [String: Any], onCompletion: @escaping(T?, Error?) -> ()) { 68 | if (reachability.isReachable) { 69 | Alamofire.request(Self.getAPI(path: path, data: queries)).validate().responseString { json in 70 | do { 71 | let jsonDecoder = JSONDecoder() 72 | if let result = json.data { 73 | let response = try jsonDecoder.decode(T.self, from: result) 74 | onCompletion(response, nil) 75 | } 76 | } catch { 77 | print("Error", error) 78 | } 79 | } 80 | } 81 | } 82 | } 83 | 84 | struct NetworkManager { 85 | func getPosts(queries: [String: Any], onCompletion: @escaping ([Post]?, Error?) -> ()) { 86 | APIs.makeGetRequest(path: "posts", queries: queries) { (res: [Post]?, error) in 87 | onCompletion(res, error) 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /MVVM-Inception/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UIApplicationSupportsIndirectInputEvents 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UIRequiredDeviceCapabilities 49 | 50 | armv7 51 | 52 | UISupportedInterfaceOrientations 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationLandscapeLeft 56 | UIInterfaceOrientationLandscapeRight 57 | 58 | UISupportedInterfaceOrientations~ipad 59 | 60 | UIInterfaceOrientationPortrait 61 | UIInterfaceOrientationPortraitUpsideDown 62 | UIInterfaceOrientationLandscapeLeft 63 | UIInterfaceOrientationLandscapeRight 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /MVVM-Inception/MVVM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shubham0812/MVVM-Tutorial/9d9dc85b7af7abacfcc3209fbfcddf7d2e8828d4/MVVM-Inception/MVVM.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MVVM-Tutorial 2 | 3 | 4 | ## Motivation 5 | 6 | I love MVVM architecture, and I've been using it for all my iOS projects. I asked developers whether they wanted to learn MVVM and this project is a result of that. 7 | 8 | ## Introduction 9 | 10 | MVVM stands for Model-View-ViewModel. It decouples the UI code from the business logic by introducing another layer/component called View-Model. 11 | 12 | View-Model contains all the logic and data manipulation and directly interacts with the Model. It's not coupled with the View (View Controller). 13 | 14 | Benefits of using MVVM- 15 | Improved testability. 16 | Ease of Use. 17 | Smaller and Modular View-Controllers. 18 | No duplicated code to updates views. 19 | 20 | 21 | ## MVVM Architecture 22 | 23 | ![MVVM](https://raw.githubusercontent.com/Shubham0812/MVVM-Tutorial/main/MVVM-Inception/MVVM.png) 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ## Spread the word! 32 | Liked the project? Just give it a star ⭐️ and spread the word! 33 | 34 | ## Credits 35 | **©** **Shubham Kumar Singh** | *2021* 36 | --------------------------------------------------------------------------------