From a95a1291bc108d222deb5a586ca8cbecd159bdc3 Mon Sep 17 00:00:00 2001 From: Lam Le V Date: Thu, 13 Feb 2020 21:37:15 +0700 Subject: [PATCH 1/2] Fetching data from api --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../UserInterfaceState.xcuserstate | Bin 0 -> 6323 bytes .../FetchingData/.gitignore | 86 ++++ .../FetchingData.xcodeproj/project.pbxproj | 463 ++++++++++++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../UserInterfaceState.xcuserstate | Bin 0 -> 17705 bytes .../xcschemes/xcschememanagement.plist | 14 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../FetchingData/AppDelegate.swift | 33 ++ .../AppIcon.appiconset/Contents.json | 98 ++++ .../Assets.xcassets/Contents.json | 6 + .../Base.lproj/LaunchScreen.storyboard | 25 + .../FetchingData/Ext/DictionaryExt.swift | 16 + .../FetchingData/FetchData/Developer.json | 25 + .../FetchingData/FetchingData/Info.plist | 64 +++ .../FetchingData/Network/Network.swift | 68 +++ .../FetchingData/Network/Target.swift | 63 +++ .../FetchingData/SceneDelegate.swift | 19 + .../ViewController/Base.lproj/Main.storyboard | 41 ++ .../ViewController/ViewController.swift | 61 +++ .../ViewController/ViewModel.swift | 47 ++ .../FetchingData/Podfile | 8 + .../FetchingData/Podfile.lock | 28 ++ .../MyPlayground.playground/Contents.swift | 30 ++ .../contents.xcplayground | 4 + 25 files changed, 1223 insertions(+) create mode 100644 05_Networking/DemoNetworking.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 05_Networking/DemoNetworking.playground/playground.xcworkspace/xcuserdata/mba0071.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 11_Fetching_Data_From_API/FetchingData/.gitignore create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/project.pbxproj create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/project.xcworkspace/xcuserdata/mba0071.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/xcuserdata/mba0071.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/AppDelegate.swift create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/Assets.xcassets/Contents.json create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/Base.lproj/LaunchScreen.storyboard create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/Ext/DictionaryExt.swift create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/FetchData/Developer.json create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/Info.plist create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/Network/Network.swift create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/Network/Target.swift create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/SceneDelegate.swift create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/Base.lproj/Main.storyboard create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/ViewController.swift create mode 100644 11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/ViewModel.swift create mode 100644 11_Fetching_Data_From_API/FetchingData/Podfile create mode 100644 11_Fetching_Data_From_API/FetchingData/Podfile.lock create mode 100644 11_Fetching_Data_From_API/MyPlayground.playground/Contents.swift create mode 100644 11_Fetching_Data_From_API/MyPlayground.playground/contents.xcplayground diff --git a/05_Networking/DemoNetworking.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/05_Networking/DemoNetworking.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/05_Networking/DemoNetworking.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/05_Networking/DemoNetworking.playground/playground.xcworkspace/xcuserdata/mba0071.xcuserdatad/UserInterfaceState.xcuserstate b/05_Networking/DemoNetworking.playground/playground.xcworkspace/xcuserdata/mba0071.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..ce10192bb6421cdc647ff18596dbb760c81a42ce GIT binary patch literal 6323 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 /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"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 7ECC8D6523F4460700E22D01 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7E805C7523F5885A00769C31 /* Target.swift in Sources */, + 7E805C7323F587E000769C31 /* Network.swift in Sources */, + 7ECC8D7123F4460700E22D01 /* ViewController.swift in Sources */, + 7ECC8D6D23F4460700E22D01 /* AppDelegate.swift in Sources */, + 7ECC8D8223F4489A00E22D01 /* ViewModel.swift in Sources */, + 7E805C7823F58C8E00769C31 /* DictionaryExt.swift in Sources */, + 7ECC8D6F23F4460700E22D01 /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 7ECC8D7223F4460700E22D01 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 7ECC8D7323F4460700E22D01 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 7ECC8D7723F4460F00E22D01 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 7ECC8D7823F4460F00E22D01 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 7ECC8D7B23F4460F00E22D01 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 7ECC8D7C23F4460F00E22D01 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 7ECC8D7E23F4460F00E22D01 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 26B24AE13E333A7FF058CF9C /* Pods-FetchingData.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = FetchingData/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = vn.asiantech.dev.FetchingData; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 7ECC8D7F23F4460F00E22D01 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EA00D0757C1D2EC69370115D /* Pods-FetchingData.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = FetchingData/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = vn.asiantech.dev.FetchingData; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7ECC8D6423F4460700E22D01 /* Build configuration list for PBXProject "FetchingData" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7ECC8D7B23F4460F00E22D01 /* Debug */, + 7ECC8D7C23F4460F00E22D01 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7ECC8D7D23F4460F00E22D01 /* Build configuration list for PBXNativeTarget "FetchingData" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7ECC8D7E23F4460F00E22D01 /* Debug */, + 7ECC8D7F23F4460F00E22D01 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 7ECC8D6123F4460700E22D01 /* Project object */; +} diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/project.xcworkspace/xcuserdata/mba0071.xcuserdatad/UserInterfaceState.xcuserstate b/11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/project.xcworkspace/xcuserdata/mba0071.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..8b61f90b1f472d807e10e2fb1796732a08baf052 GIT binary patch literal 17705 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 literal 0 HcmV?d00001 diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/xcuserdata/mba0071.xcuserdatad/xcschemes/xcschememanagement.plist b/11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/xcuserdata/mba0071.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..4c88b40 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData.xcodeproj/xcuserdata/mba0071.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + FetchingData.xcscheme_^#shared#^_ + + orderHint + 2 + + + + diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/11_Fetching_Data_From_API/FetchingData/FetchingData.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/AppDelegate.swift b/11_Fetching_Data_From_API/FetchingData/FetchingData/AppDelegate.swift new file mode 100644 index 0000000..8d1a563 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/AppDelegate.swift @@ -0,0 +1,33 @@ +// +// AppDelegate.swift +// FetchingData +// +// Created by Lam Le V. on 2/12/20. +// Copyright © 2020 Lam Le V. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } +} + diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/Assets.xcassets/AppIcon.appiconset/Contents.json b/11_Fetching_Data_From_API/FetchingData/FetchingData/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/Assets.xcassets/Contents.json b/11_Fetching_Data_From_API/FetchingData/FetchingData/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/Base.lproj/LaunchScreen.storyboard b/11_Fetching_Data_From_API/FetchingData/FetchingData/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/Ext/DictionaryExt.swift b/11_Fetching_Data_From_API/FetchingData/FetchingData/Ext/DictionaryExt.swift new file mode 100644 index 0000000..89dd2d0 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/Ext/DictionaryExt.swift @@ -0,0 +1,16 @@ +// +// DictionaryExt.swift +// FetchingData +// +// Created by Lam Le V. on 2/13/20. +// Copyright © 2020 Lam Le V. All rights reserved. +// + +import Foundation + +extension Dictionary { + + func data() -> Data? { + return (try? JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)) + } +} diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/FetchData/Developer.json b/11_Fetching_Data_From_API/FetchingData/FetchingData/FetchData/Developer.json new file mode 100644 index 0000000..6b85d4c --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/FetchData/Developer.json @@ -0,0 +1,25 @@ + +{ + "developers": [ + { + "id": 1, + "name": "Lam Le" + }, + { + "id": 2, + "name": "Tien Le" + }, + { + "id": 3, + "name": "Toan Truong" + }, + { + "id": 4, + "name": "Cuong Doan" + }, + { + "id": 5, + "name": "Thinh Nguyen" + }, + ] +} diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/Info.plist b/11_Fetching_Data_From_API/FetchingData/FetchingData/Info.plist new file mode 100644 index 0000000..2a3483c --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/Info.plist @@ -0,0 +1,64 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/Network/Network.swift b/11_Fetching_Data_From_API/FetchingData/FetchingData/Network/Network.swift new file mode 100644 index 0000000..187513b --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/Network/Network.swift @@ -0,0 +1,68 @@ +// +// Network.swift +// FetchingData +// +// Created by Lam Le V. on 2/13/20. +// Copyright © 2020 Lam Le V. All rights reserved. +// + +import Foundation +import Combine + +typealias NetworkPublisher = AnyPublisher.Error> + +final class Network { + + enum Error: Swift.Error { + case jsonFailure + case invalidResponse + case unknown + + var localizedDescription: String { + switch self { + case .jsonFailure: + return "JSON Failure" + case .invalidResponse: + return "Invalid response" + case .unknown: + return "Unknown" + } + } + } + + private let target: Target + + init(target: Target) { + self.target = target + } +} + +extension Network where T: Codable { + + func request() -> NetworkPublisher { + var request = URLRequest(url: URL(string: target.path)!) + request.timeoutInterval = 60 // Set time out + request.allHTTPHeaderFields = target.headers + request.httpMethod = target.method.rawValue + if target.method == .post { + request.httpBody = target.parameter?.data() + } + + return URLSession.shared.dataTaskPublisher(for: request).tryMap { (data, response) -> Data in + // Handle api error + guard let httpResponse = response as? HTTPURLResponse, + httpResponse.statusCode == 200 else { + throw Error.invalidResponse + } + return data + } + .decode(type: T.self, decoder: JSONDecoder()) + .mapError({ error -> Network.Error in + if let error = error as? Network.Error { + return error + } + return .unknown + }) + .eraseToAnyPublisher() + } +} diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/Network/Target.swift b/11_Fetching_Data_From_API/FetchingData/FetchingData/Network/Target.swift new file mode 100644 index 0000000..1d5c59b --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/Network/Target.swift @@ -0,0 +1,63 @@ +// +// Target.swift +// FetchingData +// +// Created by Lam Le V. on 2/13/20. +// Copyright © 2020 Lam Le V. All rights reserved. +// + +import Foundation + +public typealias Parameters = [String: Any] + +enum HTTPMethod: String { + case options = "OPTIONS" + case get = "GET" + case head = "HEAD" + case post = "POST" + case put = "PUT" + case patch = "PATCH" + case delete = "DELETE" + case trace = "TRACE" + case connect = "CONNECT" +} + +protocol TargetType { + var path: String { get } + var method: HTTPMethod { get } + var headers: [String: String]? { get } + var parameter: Parameters? { get } +} + +enum Target: TargetType { + + case developer + + var path: String { + switch self { + case .developer: + return "http://developer.com" + } + } + + var method: HTTPMethod { + switch self { + case .developer: + return .get + } + } + + var headers: [String : String]? { + switch self { + case .developer: + return nil + } + } + + var parameter: Parameters? { + switch self { + case .developer: + return nil + } + } +} diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/SceneDelegate.swift b/11_Fetching_Data_From_API/FetchingData/FetchingData/SceneDelegate.swift new file mode 100644 index 0000000..dc335a2 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/SceneDelegate.swift @@ -0,0 +1,19 @@ +// +// SceneDelegate.swift +// FetchingData +// +// Created by Lam Le V. on 2/12/20. +// Copyright © 2020 Lam Le V. All rights reserved. +// + +import UIKit + +final class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + guard let _ = (scene as? UIWindowScene) else { return } + } +} + diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/Base.lproj/Main.storyboard b/11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/Base.lproj/Main.storyboard new file mode 100644 index 0000000..6399673 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/Base.lproj/Main.storyboard @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/ViewController.swift b/11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/ViewController.swift new file mode 100644 index 0000000..cc7386d --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/ViewController.swift @@ -0,0 +1,61 @@ +// +// ViewController.swift +// FetchingData +// +// Created by Lam Le V. on 2/12/20. +// Copyright © 2020 Lam Le V. All rights reserved. +// + +import UIKit +import OHHTTPStubs +import Combine + +final class ViewController: UIViewController { + + @IBOutlet private weak var tableView: UITableView! + let viewModel = ViewModel() + var cancellable: [AnyCancellable] = [] + private var developers: [Developer] = [] + + override func viewDidLoad() { + super.viewDidLoad() + configTableView() + fetchData() + } + + private func configTableView() { + tableView.dataSource = self + tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") + } + + private func fetchData() { + // Mock server by OHHTTPStubs + stub(condition: isHost("developer.com")) { _ in + // Stub it with our "wsresponse.json" stub file (which is in same bundle as self) + let stubPath = OHPathForFile("Developer.json", type(of: self)) + return fixture(filePath: stubPath!, headers: ["Content-Type":"application/json"]) + } + // Fetch data + viewModel.fetchDevelopers.receive(on: RunLoop.main).sink(receiveCompletion: { (error) in + print(error) + }, receiveValue: { [weak self] developers in + self?.developers = developers + self?.tableView.reloadData() + }) + .store(in: &cancellable) + } +} + +extension ViewController: UITableViewDataSource { + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return developers.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) + cell.textLabel?.text = developers[indexPath.row].name + return cell + } +} + diff --git a/11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/ViewModel.swift b/11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/ViewModel.swift new file mode 100644 index 0000000..eaee9c6 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/FetchingData/ViewController/ViewModel.swift @@ -0,0 +1,47 @@ +// +// ViewModel.swift +// FetchingData +// +// Created by Lam Le V. on 2/12/20. +// Copyright © 2020 Lam Le V. All rights reserved. +// + +import Foundation +import Combine + +final class ViewModel { + + enum Error: Swift.Error { + case jsonFailure + case invalidResponse + + var localizedDescription: String { + switch self { + case .jsonFailure: + return "JSON Failure" + case .invalidResponse: + return "Invalid response" + } + } + } + + let fetchDevelopers = Network<[String: [Developer]]>(target: .developer) + .request() + .tryMap({ (value) -> [Developer] in + guard let developers = value["developers"] else { + throw Error.invalidResponse + } + return developers + }) +} + +extension ViewModel { + private struct Config { + static let path = "https://developer.com" + } +} + +struct Developer: Codable { + var name: String + var id: Int +} diff --git a/11_Fetching_Data_From_API/FetchingData/Podfile b/11_Fetching_Data_From_API/FetchingData/Podfile new file mode 100644 index 0000000..ebe72bd --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/Podfile @@ -0,0 +1,8 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '9.0' + +target 'FetchingData' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + pod 'OHHTTPStubs/Swift' +end diff --git a/11_Fetching_Data_From_API/FetchingData/Podfile.lock b/11_Fetching_Data_From_API/FetchingData/Podfile.lock new file mode 100644 index 0000000..5aaa317 --- /dev/null +++ b/11_Fetching_Data_From_API/FetchingData/Podfile.lock @@ -0,0 +1,28 @@ +PODS: + - OHHTTPStubs/Core (9.0.0) + - OHHTTPStubs/Default (9.0.0): + - OHHTTPStubs/Core + - OHHTTPStubs/JSON + - OHHTTPStubs/NSURLSession + - OHHTTPStubs/OHPathHelpers + - OHHTTPStubs/JSON (9.0.0): + - OHHTTPStubs/Core + - OHHTTPStubs/NSURLSession (9.0.0): + - OHHTTPStubs/Core + - OHHTTPStubs/OHPathHelpers (9.0.0) + - OHHTTPStubs/Swift (9.0.0): + - OHHTTPStubs/Default + +DEPENDENCIES: + - OHHTTPStubs/Swift + +SPEC REPOS: + trunk: + - OHHTTPStubs + +SPEC CHECKSUMS: + OHHTTPStubs: cb29d2a9d09a828ecb93349a2b0c64f99e0db89f + +PODFILE CHECKSUM: bcda3496294e0d92cf427b96ec684b7ea27b64af + +COCOAPODS: 1.8.4 diff --git a/11_Fetching_Data_From_API/MyPlayground.playground/Contents.swift b/11_Fetching_Data_From_API/MyPlayground.playground/Contents.swift new file mode 100644 index 0000000..e859e6d --- /dev/null +++ b/11_Fetching_Data_From_API/MyPlayground.playground/Contents.swift @@ -0,0 +1,30 @@ +import UIKit + +struct Car: Codable { + var name: String + var horsepower: Int +} + +let dict = [ + "cars": [ + [ + "name": "Toyota Prius", + "horsepower": 1 + ], + [ + "name": "Tesla 3", + "horsepower" : 3 + ], + [ + "name": "Ferrari", + "horsepower" : 999 + ] + ] +] + +if let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted) { + let cars = try? JSONDecoder().decode([String: [Car]].self, from: jsonData) + print(cars) + +} + diff --git a/11_Fetching_Data_From_API/MyPlayground.playground/contents.xcplayground b/11_Fetching_Data_From_API/MyPlayground.playground/contents.xcplayground new file mode 100644 index 0000000..5da2641 --- /dev/null +++ b/11_Fetching_Data_From_API/MyPlayground.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 7af67394d394ef3cfc1c8eb092b32d0296d34376 Mon Sep 17 00:00:00 2001 From: Lam Le V Date: Fri, 14 Feb 2020 08:29:26 +0700 Subject: [PATCH 2/2] Remove playground folder --- .../MyPlayground.playground/Contents.swift | 30 ------------------- .../contents.xcplayground | 4 --- 2 files changed, 34 deletions(-) delete mode 100644 11_Fetching_Data_From_API/MyPlayground.playground/Contents.swift delete mode 100644 11_Fetching_Data_From_API/MyPlayground.playground/contents.xcplayground diff --git a/11_Fetching_Data_From_API/MyPlayground.playground/Contents.swift b/11_Fetching_Data_From_API/MyPlayground.playground/Contents.swift deleted file mode 100644 index e859e6d..0000000 --- a/11_Fetching_Data_From_API/MyPlayground.playground/Contents.swift +++ /dev/null @@ -1,30 +0,0 @@ -import UIKit - -struct Car: Codable { - var name: String - var horsepower: Int -} - -let dict = [ - "cars": [ - [ - "name": "Toyota Prius", - "horsepower": 1 - ], - [ - "name": "Tesla 3", - "horsepower" : 3 - ], - [ - "name": "Ferrari", - "horsepower" : 999 - ] - ] -] - -if let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted) { - let cars = try? JSONDecoder().decode([String: [Car]].self, from: jsonData) - print(cars) - -} - diff --git a/11_Fetching_Data_From_API/MyPlayground.playground/contents.xcplayground b/11_Fetching_Data_From_API/MyPlayground.playground/contents.xcplayground deleted file mode 100644 index 5da2641..0000000 --- a/11_Fetching_Data_From_API/MyPlayground.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file