From cc8af5dc8270dfae689065bcd06e57ac7253287f Mon Sep 17 00:00:00 2001 From: ckkim817 Date: Fri, 12 May 2023 17:22:46 +0900 Subject: [PATCH 1/5] =?UTF-8?q?4=EC=B0=A8=20=EC=84=B8=EB=AF=B8=EB=82=98=20?= =?UTF-8?q?=EC=8B=A4=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project.pbxproj | 63 ++++++++++++++++ .../xcshareddata/swiftpm/Package.resolved | 9 +++ .../Application/SceneDelegate.swift | 2 +- 32th-Sopt-Seminar/Info.plist | 11 +++ .../Fourth-Seminar/Config.swift | 53 ++++++++++++++ .../CurrentWeatherService.swift | 62 ++++++++++++++++ .../Fourth-Seminar/DataModel.swift | 35 +++++++++ .../Fourth-Seminar/NetworkResult.swift | 16 +++++ .../Fourth-Seminar/SignUpResponse.swift | 18 +++++ .../Fourth-Seminar/SignUpService.swift | 72 +++++++++++++++++++ .../ViewController_FourthSeminar.swift | 33 +++++++++ .../ViewController_WeatherAPI.swift | 32 +++++++++ 12 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/Config.swift create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/CurrentWeatherService.swift create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/DataModel.swift create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/NetworkResult.swift create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/SignUpResponse.swift create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/SignUpService.swift create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_FourthSeminar.swift create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_WeatherAPI.swift diff --git a/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj b/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj index 038e298..d8e9cd3 100644 --- a/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj +++ b/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj @@ -36,6 +36,15 @@ DF1841762A052D37001A466A /* MyPassView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841752A052D37001A466A /* MyPassView.swift */; }; DF1841792A052ED4001A466A /* BuyPassView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841782A052ED4001A466A /* BuyPassView.swift */; }; DF18417B2A052FFD001A466A /* UILabel+.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF18417A2A052FFD001A466A /* UILabel+.swift */; }; + DF18417E2A062437001A466A /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = DF18417D2A062437001A466A /* Alamofire */; }; + DF1841812A062548001A466A /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841802A062548001A466A /* Config.swift */; }; + DF1841832A06257B001A466A /* NetworkResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841822A06257B001A466A /* NetworkResult.swift */; }; + DF1841852A06282E001A466A /* SignUpService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841842A06282E001A466A /* SignUpService.swift */; }; + DF1841872A0628F2001A466A /* ViewController_FourthSeminar.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841862A0628F2001A466A /* ViewController_FourthSeminar.swift */; }; + DF1841892A062969001A466A /* SignUpResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841882A062969001A466A /* SignUpResponse.swift */; }; + DF18418B2A0DF337001A466A /* DataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF18418A2A0DF336001A466A /* DataModel.swift */; }; + DF18418D2A0DF4F8001A466A /* CurrentWeatherService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF18418C2A0DF4F8001A466A /* CurrentWeatherService.swift */; }; + DF18418F2A0E00AA001A466A /* ViewController_WeatherAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF18418E2A0E00AA001A466A /* ViewController_WeatherAPI.swift */; }; DF93B64029E133E400A1CBD0 /* FirstViewController_DelegatePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF93B63F29E133E400A1CBD0 /* FirstViewController_DelegatePattern.swift */; }; DF93B64229E1344F00A1CBD0 /* SecondViewController_DelegatePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF93B64129E1344F00A1CBD0 /* SecondViewController_DelegatePattern.swift */; }; DF93B64429E1386600A1CBD0 /* FirstViewController_Closure.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF93B64329E1386600A1CBD0 /* FirstViewController_Closure.swift */; }; @@ -85,6 +94,14 @@ DF1841752A052D37001A466A /* MyPassView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPassView.swift; sourceTree = ""; }; DF1841782A052ED4001A466A /* BuyPassView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuyPassView.swift; sourceTree = ""; }; DF18417A2A052FFD001A466A /* UILabel+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+.swift"; sourceTree = ""; }; + DF1841802A062548001A466A /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; + DF1841822A06257B001A466A /* NetworkResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkResult.swift; sourceTree = ""; }; + DF1841842A06282E001A466A /* SignUpService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpService.swift; sourceTree = ""; }; + DF1841862A0628F2001A466A /* ViewController_FourthSeminar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController_FourthSeminar.swift; sourceTree = ""; }; + DF1841882A062969001A466A /* SignUpResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpResponse.swift; sourceTree = ""; }; + DF18418A2A0DF336001A466A /* DataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataModel.swift; sourceTree = ""; }; + DF18418C2A0DF4F8001A466A /* CurrentWeatherService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentWeatherService.swift; sourceTree = ""; }; + DF18418E2A0E00AA001A466A /* ViewController_WeatherAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController_WeatherAPI.swift; sourceTree = ""; }; DF93B63F29E133E400A1CBD0 /* FirstViewController_DelegatePattern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstViewController_DelegatePattern.swift; sourceTree = ""; }; DF93B64129E1344F00A1CBD0 /* SecondViewController_DelegatePattern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondViewController_DelegatePattern.swift; sourceTree = ""; }; DF93B64329E1386600A1CBD0 /* FirstViewController_Closure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstViewController_Closure.swift; sourceTree = ""; }; @@ -107,6 +124,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DF18417E2A062437001A466A /* Alamofire in Frameworks */, DF93B64B29E13ED200A1CBD0 /* SnapKit in Frameworks */, DF93B64E29E141ED00A1CBD0 /* Then in Frameworks */, ); @@ -297,6 +315,21 @@ path = Cell; sourceTree = ""; }; + DF18417F2A062530001A466A /* Fourth-Seminar */ = { + isa = PBXGroup; + children = ( + DF1841802A062548001A466A /* Config.swift */, + DF1841822A06257B001A466A /* NetworkResult.swift */, + DF1841842A06282E001A466A /* SignUpService.swift */, + DF1841862A0628F2001A466A /* ViewController_FourthSeminar.swift */, + DF1841882A062969001A466A /* SignUpResponse.swift */, + DF18418A2A0DF336001A466A /* DataModel.swift */, + DF18418C2A0DF4F8001A466A /* CurrentWeatherService.swift */, + DF18418E2A0E00AA001A466A /* ViewController_WeatherAPI.swift */, + ); + path = "Fourth-Seminar"; + sourceTree = ""; + }; DF93B64729E13B7200A1CBD0 /* First-Seminar */ = { isa = PBXGroup; children = ( @@ -346,6 +379,7 @@ DF93B64729E13B7200A1CBD0 /* First-Seminar */, DF93B64829E13B9900A1CBD0 /* Second-Seminar */, DF18411D29F3A942001A466A /* Third-Seminar */, + DF18417F2A062530001A466A /* Fourth-Seminar */, ); path = "32th-Sopt-Seminar"; sourceTree = ""; @@ -369,6 +403,7 @@ packageProductDependencies = ( DF93B64A29E13ED200A1CBD0 /* SnapKit */, DF93B64D29E141ED00A1CBD0 /* Then */, + DF18417D2A062437001A466A /* Alamofire */, ); productName = "32th-Sopt-First-Seminar"; productReference = DFA4A01529D8095100BFB46A /* 32th-Sopt-Seminar.app */; @@ -401,6 +436,7 @@ packageReferences = ( DF93B64929E13ED200A1CBD0 /* XCRemoteSwiftPackageReference "SnapKit" */, DF93B64C29E141ED00A1CBD0 /* XCRemoteSwiftPackageReference "Then" */, + DF18417C2A062437001A466A /* XCRemoteSwiftPackageReference "Alamofire" */, ); productRefGroup = DFA4A01629D8095100BFB46A /* Products */; projectDirPath = ""; @@ -451,10 +487,13 @@ DF1841762A052D37001A466A /* MyPassView.swift in Sources */, DF1841672A04FCFE001A466A /* UINavigationItem+.swift in Sources */, DF18416C2A052195001A466A /* UITableView+.swift in Sources */, + DF18418F2A0E00AA001A466A /* ViewController_WeatherAPI.swift in Sources */, + DF1841872A0628F2001A466A /* ViewController_FourthSeminar.swift in Sources */, DF1841572A04220B001A466A /* BaseViewController.swift in Sources */, DF18413729F3C86C001A466A /* UIView+.swift in Sources */, DFA4A01929D8095100BFB46A /* AppDelegate.swift in Sources */, DFA4A02D29D80BAA00BFB46A /* FirstViewController_1st_Seminar.swift in Sources */, + DF18418D2A0DF4F8001A466A /* CurrentWeatherService.swift in Sources */, DF18414629FA67CB001A466A /* Color.swift in Sources */, DF18415B2A042E5A001A466A /* Int+.swift in Sources */, DF93B64229E1344F00A1CBD0 /* SecondViewController_DelegatePattern.swift in Sources */, @@ -464,9 +503,14 @@ DF1841742A052C83001A466A /* MyProfileView.swift in Sources */, DF18416E2A052235001A466A /* NSObject+.swift in Sources */, DF18415D2A043575001A466A /* MyPageViewController.swift in Sources */, + DF18418B2A0DF337001A466A /* DataModel.swift in Sources */, DFA4A02F29D8105400BFB46A /* SecondViewController_1st_Seminar.swift in Sources */, + DF1841892A062969001A466A /* SignUpResponse.swift in Sources */, DF18413529F3BCC3001A466A /* UIImage+.swift in Sources */, DFA4A01B29D8095100BFB46A /* SceneDelegate.swift in Sources */, + DF1841852A06282E001A466A /* SignUpService.swift in Sources */, + DF1841812A062548001A466A /* Config.swift in Sources */, + DF1841832A06257B001A466A /* NetworkResult.swift in Sources */, DF18412B29F3B549001A466A /* CarrotViewController.swift in Sources */, DF1841652A04ED3D001A466A /* MyPageTableViewCell.swift in Sources */, ); @@ -605,6 +649,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + BASE_URL = "http://54.180.123.11"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 8MTU4Q38X7; @@ -624,6 +669,8 @@ SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + WEATHER_API = 2e4e7c115a23a0ec023cd170849b696a; + WEATHER_URL = "https://api.openweathermap.org/data/2.5/weather?"; }; name = Debug; }; @@ -632,6 +679,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + BASE_URL = "http://54.180.123.11"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 8MTU4Q38X7; @@ -651,6 +699,8 @@ SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + WEATHER_API = 2e4e7c115a23a0ec023cd170849b696a; + WEATHER_URL = "https://api.openweathermap.org/data/2.5/weather?"; }; name = Release; }; @@ -678,6 +728,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + DF18417C2A062437001A466A /* XCRemoteSwiftPackageReference "Alamofire" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Alamofire/Alamofire.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.0.0; + }; + }; DF93B64929E13ED200A1CBD0 /* XCRemoteSwiftPackageReference "SnapKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/SnapKit/SnapKit.git"; @@ -697,6 +755,11 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + DF18417D2A062437001A466A /* Alamofire */ = { + isa = XCSwiftPackageProductDependency; + package = DF18417C2A062437001A466A /* XCRemoteSwiftPackageReference "Alamofire" */; + productName = Alamofire; + }; DF93B64A29E13ED200A1CBD0 /* SnapKit */ = { isa = XCSwiftPackageProductDependency; package = DF93B64929E13ED200A1CBD0 /* XCRemoteSwiftPackageReference "SnapKit" */; diff --git a/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b29f983..ebe0fe1 100644 --- a/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,14 @@ { "pins" : [ + { + "identity" : "alamofire", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Alamofire/Alamofire.git", + "state" : { + "revision" : "78424be314842833c04bc3bef5b72e85fff99204", + "version" : "5.6.4" + } + }, { "identity" : "snapkit", "kind" : "remoteSourceControl", diff --git a/32th-Sopt-Seminar/Application/SceneDelegate.swift b/32th-Sopt-Seminar/Application/SceneDelegate.swift index d1e6b60..ab9bea5 100644 --- a/32th-Sopt-Seminar/Application/SceneDelegate.swift +++ b/32th-Sopt-Seminar/Application/SceneDelegate.swift @@ -18,7 +18,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // 2. self.window = UIWindow(windowScene: windowScene) // 3. - let navigationController = UINavigationController(rootViewController: MyPageViewController()) + let navigationController = UINavigationController(rootViewController: ViewController_WeatherAPI()) self.window?.rootViewController = navigationController // 4. self.window?.makeKeyAndVisible() diff --git a/32th-Sopt-Seminar/Info.plist b/32th-Sopt-Seminar/Info.plist index 0eb786d..5094d23 100644 --- a/32th-Sopt-Seminar/Info.plist +++ b/32th-Sopt-Seminar/Info.plist @@ -2,6 +2,17 @@ + WEATHER_API + $(WEATHER_API) + WEATHER_URL + $(WEATHER_URL) + BASE_URL + $(BASE_URL) + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + UIApplicationSceneManifest UIApplicationSupportsMultipleScenes diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/Config.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/Config.swift new file mode 100644 index 0000000..5a74a0b --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/Config.swift @@ -0,0 +1,53 @@ +// +// Config.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/06. +// + +import Foundation + +enum Config { + enum Keys { + enum Plist { + static let baseURL = "BASE_URL" + static let weatherURL = "WEATHER_URL" + static let weatherAPI = "WEATHER_API" + } + } + + private static let infoDictionary: [String: Any] = { + guard let dict = Bundle.main.infoDictionary else { + fatalError("plist cannot found.") + } + + return dict + }() +} + +extension Config { + + static let baseURL: String = { + guard let key = Config.infoDictionary[Keys.Plist.baseURL] as? String else { + fatalError("Base URL is not set in plist for this configuration.") + } + + return key + }() + + static let weatherURL: String = { + guard let key = Config.infoDictionary[Keys.Plist.weatherURL] as? String else { + fatalError("Weather URL is not set in plist for this configuration.") + } + + return key + }() + + static let weatherAPI: String = { + guard let key = Config.infoDictionary[Keys.Plist.weatherAPI] as? String else { + fatalError("Weather API is not set in plist for this configuration.") + } + + return key + }() +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/CurrentWeatherService.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/CurrentWeatherService.swift new file mode 100644 index 0000000..ca7b5af --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/CurrentWeatherService.swift @@ -0,0 +1,62 @@ +// +// CurrentWeatherService.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/12. +// + +import Foundation + +import Alamofire + +final class CurrentWeatherService { + + static let get = CurrentWeatherService() + + private init() {} + + func loadWeather(city: String, + completion: @escaping (NetworkResult) -> Void) { + + let url = Config.weatherURL + "q=\(city)" + "&appid=" + Config.weatherAPI + + let header: HTTPHeaders = ["Content-Type" : "application/json"] + + let dataRequest = AF.request(url, method: .get, headers: header) + + dataRequest.responseData { response in + switch response.result { + case .success: + guard let statusCode = response.response?.statusCode else { return } + guard let value = response.value else { return } + let networkResult = self.judgeStatus(by: statusCode, value) + completion(networkResult) + case .failure: + completion(.networkErr) + } + } + } + + private func judgeStatus(by statusCode: Int, _ data: Data) -> NetworkResult { + + switch statusCode { + case 200: + return isValidData(data: data) + case 400, 409: + return isValidData(data: data) + case 500: + return .serverErr + default: + return .networkErr + } + } + + private func isValidData(data: Data) -> NetworkResult { + + let decoder = JSONDecoder() + + guard let decodedData = try? decoder.decode(Weathers.self, from: data) else { return .pathErr } + + return .success(decodedData as Any) + } +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/DataModel.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/DataModel.swift new file mode 100644 index 0000000..69639c5 --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/DataModel.swift @@ -0,0 +1,35 @@ +// +// DataModel.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/12. +// + +import Foundation + +struct Weathers: Codable { + let weather: [Weather] + let main: Main + let wind: Wind + let name: String +} + +struct Weather: Codable { + let id: Int + let main: String + let description: String + let icon: String +} + +struct Main: Codable { + let temp: Double + let feels_like: Double + let temp_min: Double + let temp_max: Double + let pressure: Int + let humidity: Int +} + +struct Wind: Codable { + let speed: Double +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/NetworkResult.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/NetworkResult.swift new file mode 100644 index 0000000..e46cd4a --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/NetworkResult.swift @@ -0,0 +1,16 @@ +// +// NetworkResult.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/06. +// + +import Foundation + +enum NetworkResult { + case success(T) // 서버 통신 성공 + case requestErr(T) // 요청에러 발생 + case pathErr // 경로 에러 + case serverErr // 서버 내부 에러 + case networkErr // 네트워크 연결 실패 +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/SignUpResponse.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/SignUpResponse.swift new file mode 100644 index 0000000..98c0f8f --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/SignUpResponse.swift @@ -0,0 +1,18 @@ +// +// SignUpResponse.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/06. +// + +struct SignUpResponse: Codable { + let code: Int + let success: Bool? + let message: String + let data: SignUpData? +} + +struct SignUpData: Codable { + let userId: Int + let nickname: String +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/SignUpService.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/SignUpService.swift new file mode 100644 index 0000000..6f023c3 --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/SignUpService.swift @@ -0,0 +1,72 @@ +// +// SignUpService.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/06. +// + +import Foundation + +import Alamofire + +final class SignUpService { + + static let shared = SignUpService() + + private init() {} + + func signUp(email: String, + nickname: String, + password: String, + completion: @escaping (NetworkResult) -> Void) { + + let url = Config.baseURL + "/user/signup" + let header: HTTPHeaders = ["Content-Type" : "application/json"] + let body: Parameters = [ + "password": password, + "email": email, + "nickname": nickname, + ] + + let dataRequest = AF.request(url, + method: .post, + parameters: body, + encoding: JSONEncoding.default, + headers: header) + + dataRequest.responseData { response in + switch response.result { + case .success: + guard let statusCode = response.response?.statusCode else { return } + guard let value = response.value else { return } + let networkResult = self.judgeStatus(by: statusCode, value) + completion(networkResult) + case .failure: + completion(.networkErr) + } + } + } + + private func judgeStatus(by statusCode: Int, _ data: Data) -> NetworkResult { + + switch statusCode { + case 201: + return isValidData(data: data) + case 400, 409: + return isValidData(data: data) + case 500: + return .serverErr + default: + return .networkErr + } + } + + private func isValidData(data: Data) -> NetworkResult { + + let decoder = JSONDecoder() + + guard let decodedData = try? decoder.decode(SignUpResponse.self, from: data) else { return .pathErr } + + return .success(decodedData as Any) + } +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_FourthSeminar.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_FourthSeminar.swift new file mode 100644 index 0000000..f43a325 --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_FourthSeminar.swift @@ -0,0 +1,33 @@ +// +// ViewController_FourthSeminar.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/06. +// + +import UIKit + +final class ViewController_FourthSeminar: UIViewController { + + override func viewDidLoad() { + + super.viewDidLoad() + + signUp() + } + + private func signUp() { + + SignUpService.shared.signUp(email: "seungchan@naver.com", + nickname: "godios", + password: "Qwer1234!") { response in + switch response { + case .success(let data): + guard let data = data as? SignUpResponse else { return } + dump(data) + default: + return + } + } + } +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_WeatherAPI.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_WeatherAPI.swift new file mode 100644 index 0000000..bf7124a --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_WeatherAPI.swift @@ -0,0 +1,32 @@ +// +// ViewController_WeatherAPI.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/12. +// + +import UIKit + +class ViewController_WeatherAPI: UIViewController { + + override func viewDidLoad() { + + super.viewDidLoad() + + loadWeather() + } + + private func loadWeather() { + + CurrentWeatherService.get.loadWeather(city: "seoul") { response in + switch response { + case .success(let data): + guard let data = data as? Weathers else { return } + dump(data) + default: + print("tlqkftlqkf") + return + } + } + } +} From ca8602f08cf33a2f66bd4b432530d1783db517cc Mon Sep 17 00:00:00 2001 From: ckkim817 Date: Fri, 12 May 2023 21:34:13 +0900 Subject: [PATCH 2/5] =?UTF-8?q?plist,=20config,=20Data=20Model=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MovieInformation의 Data Model입니다 ... --- .../project.pbxproj | 14 +++++-- 32th-Sopt-Seminar/Info.plist | 2 + .../Fourth-Seminar/Config.swift | 9 +++++ .../Fourth-Seminar/MovieInformation.swift | 37 +++++++++++++++++++ .../{DataModel.swift => Weathers.swift} | 2 +- 5 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift rename 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/{DataModel.swift => Weathers.swift} (96%) diff --git a/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj b/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj index d8e9cd3..29a351d 100644 --- a/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj +++ b/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj @@ -42,9 +42,10 @@ DF1841852A06282E001A466A /* SignUpService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841842A06282E001A466A /* SignUpService.swift */; }; DF1841872A0628F2001A466A /* ViewController_FourthSeminar.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841862A0628F2001A466A /* ViewController_FourthSeminar.swift */; }; DF1841892A062969001A466A /* SignUpResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841882A062969001A466A /* SignUpResponse.swift */; }; - DF18418B2A0DF337001A466A /* DataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF18418A2A0DF336001A466A /* DataModel.swift */; }; + DF18418B2A0DF337001A466A /* Weathers.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF18418A2A0DF336001A466A /* Weathers.swift */; }; DF18418D2A0DF4F8001A466A /* CurrentWeatherService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF18418C2A0DF4F8001A466A /* CurrentWeatherService.swift */; }; DF18418F2A0E00AA001A466A /* ViewController_WeatherAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF18418E2A0E00AA001A466A /* ViewController_WeatherAPI.swift */; }; + DF1841912A0E668B001A466A /* MovieInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841902A0E668B001A466A /* MovieInformation.swift */; }; DF93B64029E133E400A1CBD0 /* FirstViewController_DelegatePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF93B63F29E133E400A1CBD0 /* FirstViewController_DelegatePattern.swift */; }; DF93B64229E1344F00A1CBD0 /* SecondViewController_DelegatePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF93B64129E1344F00A1CBD0 /* SecondViewController_DelegatePattern.swift */; }; DF93B64429E1386600A1CBD0 /* FirstViewController_Closure.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF93B64329E1386600A1CBD0 /* FirstViewController_Closure.swift */; }; @@ -99,9 +100,10 @@ DF1841842A06282E001A466A /* SignUpService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpService.swift; sourceTree = ""; }; DF1841862A0628F2001A466A /* ViewController_FourthSeminar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController_FourthSeminar.swift; sourceTree = ""; }; DF1841882A062969001A466A /* SignUpResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpResponse.swift; sourceTree = ""; }; - DF18418A2A0DF336001A466A /* DataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataModel.swift; sourceTree = ""; }; + DF18418A2A0DF336001A466A /* Weathers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Weathers.swift; sourceTree = ""; }; DF18418C2A0DF4F8001A466A /* CurrentWeatherService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentWeatherService.swift; sourceTree = ""; }; DF18418E2A0E00AA001A466A /* ViewController_WeatherAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController_WeatherAPI.swift; sourceTree = ""; }; + DF1841902A0E668B001A466A /* MovieInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieInformation.swift; sourceTree = ""; }; DF93B63F29E133E400A1CBD0 /* FirstViewController_DelegatePattern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstViewController_DelegatePattern.swift; sourceTree = ""; }; DF93B64129E1344F00A1CBD0 /* SecondViewController_DelegatePattern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondViewController_DelegatePattern.swift; sourceTree = ""; }; DF93B64329E1386600A1CBD0 /* FirstViewController_Closure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstViewController_Closure.swift; sourceTree = ""; }; @@ -323,9 +325,10 @@ DF1841842A06282E001A466A /* SignUpService.swift */, DF1841862A0628F2001A466A /* ViewController_FourthSeminar.swift */, DF1841882A062969001A466A /* SignUpResponse.swift */, - DF18418A2A0DF336001A466A /* DataModel.swift */, + DF18418A2A0DF336001A466A /* Weathers.swift */, DF18418C2A0DF4F8001A466A /* CurrentWeatherService.swift */, DF18418E2A0E00AA001A466A /* ViewController_WeatherAPI.swift */, + DF1841902A0E668B001A466A /* MovieInformation.swift */, ); path = "Fourth-Seminar"; sourceTree = ""; @@ -473,6 +476,7 @@ DF18414A29FA6BFA001A466A /* Image.swift in Sources */, DF18412D29F3B744001A466A /* CarrotTableViewCell.swift in Sources */, DF1841592A0422D3001A466A /* BaseView.swift in Sources */, + DF1841912A0E668B001A466A /* MovieInformation.swift in Sources */, DF1841602A04E1AA001A466A /* MyPage.swift in Sources */, DF18412929F3AD9F001A466A /* CommonView.swift in Sources */, DF18413029F3B885001A466A /* Carrot.swift in Sources */, @@ -503,7 +507,7 @@ DF1841742A052C83001A466A /* MyProfileView.swift in Sources */, DF18416E2A052235001A466A /* NSObject+.swift in Sources */, DF18415D2A043575001A466A /* MyPageViewController.swift in Sources */, - DF18418B2A0DF337001A466A /* DataModel.swift in Sources */, + DF18418B2A0DF337001A466A /* Weathers.swift in Sources */, DFA4A02F29D8105400BFB46A /* SecondViewController_1st_Seminar.swift in Sources */, DF1841892A062969001A466A /* SignUpResponse.swift in Sources */, DF18413529F3BCC3001A466A /* UIImage+.swift in Sources */, @@ -669,6 +673,7 @@ SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + TMDB_URL = "https://api.themoviedb.org/3/search/movie?api_key=182d505d38c0dff20137f9a1ffc44888&query="; WEATHER_API = 2e4e7c115a23a0ec023cd170849b696a; WEATHER_URL = "https://api.openweathermap.org/data/2.5/weather?"; }; @@ -699,6 +704,7 @@ SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + TMDB_URL = "https://api.themoviedb.org/3/search/movie?api_key=182d505d38c0dff20137f9a1ffc44888&query="; WEATHER_API = 2e4e7c115a23a0ec023cd170849b696a; WEATHER_URL = "https://api.openweathermap.org/data/2.5/weather?"; }; diff --git a/32th-Sopt-Seminar/Info.plist b/32th-Sopt-Seminar/Info.plist index 5094d23..e29e9f1 100644 --- a/32th-Sopt-Seminar/Info.plist +++ b/32th-Sopt-Seminar/Info.plist @@ -2,6 +2,8 @@ + TMDB_URL + $(TMDB_URL) WEATHER_API $(WEATHER_API) WEATHER_URL diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/Config.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/Config.swift index 5a74a0b..d19ef5b 100644 --- a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/Config.swift +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/Config.swift @@ -13,6 +13,7 @@ enum Config { static let baseURL = "BASE_URL" static let weatherURL = "WEATHER_URL" static let weatherAPI = "WEATHER_API" + static let tmdbURL = "TMDB_URL" } } @@ -50,4 +51,12 @@ extension Config { return key }() + + static let tmdbURL: String = { + guard let key = Config.infoDictionary[Keys.Plist.tmdbURL] as? String else { + fatalError("TMDB URL is not set in plist for this configuration.") + } + + return key + }() } diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift new file mode 100644 index 0000000..0b7613c --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift @@ -0,0 +1,37 @@ +// +// MovieInformation.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/12. +// + +import Foundation + +struct MovieInformation: Codable { + let posterPath: String + let adult: Bool + let overview, releaseDate: String + let genreIDS: [Int] + let id: Int + let originalTitle, originalLanguage, title, backdropPath: String + let popularity: Double + let voteCount: Int + let video: Bool + let voteAverage: Double + + enum CodingKeys: String, CodingKey { + case posterPath = "poster_path" + case adult, overview + case releaseDate = "release_date" + case genreIDS = "genre_ids" + case id + case originalTitle = "original_title" + case originalLanguage = "original_language" + case title + case backdropPath = "backdrop_path" + case popularity + case voteCount = "vote_count" + case video + case voteAverage = "vote_average" + } +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/DataModel.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/Weathers.swift similarity index 96% rename from 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/DataModel.swift rename to 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/Weathers.swift index 69639c5..7c49b9c 100644 --- a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/DataModel.swift +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/Weathers.swift @@ -1,5 +1,5 @@ // -// DataModel.swift +// Weathers.swift // 32th-Sopt-Seminar // // Created by kyun on 2023/05/12. From c8a2788069767c4e182e609aca38acc6b5e813a1 Mon Sep 17 00:00:00 2001 From: ckkim817 Date: Fri, 12 May 2023 23:31:12 +0900 Subject: [PATCH 3/5] =?UTF-8?q?4=EC=B0=A8=20=EC=84=B8=EB=AF=B8=EB=82=98=20?= =?UTF-8?q?=EA=B3=BC=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project.pbxproj | 20 +++++ .../Application/SceneDelegate.swift | 2 +- .../CurrentWeatherService.swift | 4 +- .../Fourth-Seminar/ImageCacheManager.swift | 62 +++++++++++++++ .../Fourth-Seminar/MovieDataModel.swift | 15 ++++ .../Fourth-Seminar/MovieInformation.swift | 48 ++++++----- .../MovieInformationService.swift | 64 +++++++++++++++ .../Fourth-Seminar/MovieTableViewCell.swift | 76 ++++++++++++++++++ .../ViewController_TMDBAPI.swift | 79 +++++++++++++++++++ 9 files changed, 349 insertions(+), 21 deletions(-) create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ImageCacheManager.swift create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieDataModel.swift create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieTableViewCell.swift create mode 100644 32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_TMDBAPI.swift diff --git a/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj b/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj index 29a351d..2a75ce3 100644 --- a/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj +++ b/32th-Sopt-Seminar/32th-Sopt-Seminar.xcodeproj/project.pbxproj @@ -46,6 +46,11 @@ DF18418D2A0DF4F8001A466A /* CurrentWeatherService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF18418C2A0DF4F8001A466A /* CurrentWeatherService.swift */; }; DF18418F2A0E00AA001A466A /* ViewController_WeatherAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF18418E2A0E00AA001A466A /* ViewController_WeatherAPI.swift */; }; DF1841912A0E668B001A466A /* MovieInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841902A0E668B001A466A /* MovieInformation.swift */; }; + DF1841932A0E6C08001A466A /* MovieInformationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841922A0E6C08001A466A /* MovieInformationService.swift */; }; + DF1841952A0E6F30001A466A /* ViewController_TMDBAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841942A0E6F30001A466A /* ViewController_TMDBAPI.swift */; }; + DF1841972A0E7A17001A466A /* MovieTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841962A0E7A17001A466A /* MovieTableViewCell.swift */; }; + DF1841992A0E8026001A466A /* MovieDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF1841982A0E8026001A466A /* MovieDataModel.swift */; }; + DF18419B2A0E831A001A466A /* ImageCacheManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF18419A2A0E831A001A466A /* ImageCacheManager.swift */; }; DF93B64029E133E400A1CBD0 /* FirstViewController_DelegatePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF93B63F29E133E400A1CBD0 /* FirstViewController_DelegatePattern.swift */; }; DF93B64229E1344F00A1CBD0 /* SecondViewController_DelegatePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF93B64129E1344F00A1CBD0 /* SecondViewController_DelegatePattern.swift */; }; DF93B64429E1386600A1CBD0 /* FirstViewController_Closure.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF93B64329E1386600A1CBD0 /* FirstViewController_Closure.swift */; }; @@ -104,6 +109,11 @@ DF18418C2A0DF4F8001A466A /* CurrentWeatherService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentWeatherService.swift; sourceTree = ""; }; DF18418E2A0E00AA001A466A /* ViewController_WeatherAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController_WeatherAPI.swift; sourceTree = ""; }; DF1841902A0E668B001A466A /* MovieInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieInformation.swift; sourceTree = ""; }; + DF1841922A0E6C08001A466A /* MovieInformationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieInformationService.swift; sourceTree = ""; }; + DF1841942A0E6F30001A466A /* ViewController_TMDBAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController_TMDBAPI.swift; sourceTree = ""; }; + DF1841962A0E7A17001A466A /* MovieTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieTableViewCell.swift; sourceTree = ""; }; + DF1841982A0E8026001A466A /* MovieDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieDataModel.swift; sourceTree = ""; }; + DF18419A2A0E831A001A466A /* ImageCacheManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCacheManager.swift; sourceTree = ""; }; DF93B63F29E133E400A1CBD0 /* FirstViewController_DelegatePattern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstViewController_DelegatePattern.swift; sourceTree = ""; }; DF93B64129E1344F00A1CBD0 /* SecondViewController_DelegatePattern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondViewController_DelegatePattern.swift; sourceTree = ""; }; DF93B64329E1386600A1CBD0 /* FirstViewController_Closure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstViewController_Closure.swift; sourceTree = ""; }; @@ -329,6 +339,11 @@ DF18418C2A0DF4F8001A466A /* CurrentWeatherService.swift */, DF18418E2A0E00AA001A466A /* ViewController_WeatherAPI.swift */, DF1841902A0E668B001A466A /* MovieInformation.swift */, + DF1841922A0E6C08001A466A /* MovieInformationService.swift */, + DF1841942A0E6F30001A466A /* ViewController_TMDBAPI.swift */, + DF1841962A0E7A17001A466A /* MovieTableViewCell.swift */, + DF1841982A0E8026001A466A /* MovieDataModel.swift */, + DF18419A2A0E831A001A466A /* ImageCacheManager.swift */, ); path = "Fourth-Seminar"; sourceTree = ""; @@ -479,6 +494,7 @@ DF1841912A0E668B001A466A /* MovieInformation.swift in Sources */, DF1841602A04E1AA001A466A /* MyPage.swift in Sources */, DF18412929F3AD9F001A466A /* CommonView.swift in Sources */, + DF1841992A0E8026001A466A /* MovieDataModel.swift in Sources */, DF18413029F3B885001A466A /* Carrot.swift in Sources */, DF1841722A052BF9001A466A /* MyPageHeaderView.swift in Sources */, DF1841792A052ED4001A466A /* BuyPassView.swift in Sources */, @@ -486,17 +502,21 @@ DF18412529F3ABC6001A466A /* FirstViewController_ThirdSeminar.swift in Sources */, DF93B64629E1389600A1CBD0 /* SecondViewController_Closure.swift in Sources */, DFA4A01D29D8095100BFB46A /* ViewController.swift in Sources */, + DF1841972A0E7A17001A466A /* MovieTableViewCell.swift in Sources */, DF93B64029E133E400A1CBD0 /* FirstViewController_DelegatePattern.swift in Sources */, DF93B65629E152E500A1CBD0 /* FirstViewController_Practice1.swift in Sources */, DF1841762A052D37001A466A /* MyPassView.swift in Sources */, DF1841672A04FCFE001A466A /* UINavigationItem+.swift in Sources */, DF18416C2A052195001A466A /* UITableView+.swift in Sources */, DF18418F2A0E00AA001A466A /* ViewController_WeatherAPI.swift in Sources */, + DF1841932A0E6C08001A466A /* MovieInformationService.swift in Sources */, DF1841872A0628F2001A466A /* ViewController_FourthSeminar.swift in Sources */, DF1841572A04220B001A466A /* BaseViewController.swift in Sources */, + DF1841952A0E6F30001A466A /* ViewController_TMDBAPI.swift in Sources */, DF18413729F3C86C001A466A /* UIView+.swift in Sources */, DFA4A01929D8095100BFB46A /* AppDelegate.swift in Sources */, DFA4A02D29D80BAA00BFB46A /* FirstViewController_1st_Seminar.swift in Sources */, + DF18419B2A0E831A001A466A /* ImageCacheManager.swift in Sources */, DF18418D2A0DF4F8001A466A /* CurrentWeatherService.swift in Sources */, DF18414629FA67CB001A466A /* Color.swift in Sources */, DF18415B2A042E5A001A466A /* Int+.swift in Sources */, diff --git a/32th-Sopt-Seminar/Application/SceneDelegate.swift b/32th-Sopt-Seminar/Application/SceneDelegate.swift index ab9bea5..ff637ae 100644 --- a/32th-Sopt-Seminar/Application/SceneDelegate.swift +++ b/32th-Sopt-Seminar/Application/SceneDelegate.swift @@ -18,7 +18,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // 2. self.window = UIWindow(windowScene: windowScene) // 3. - let navigationController = UINavigationController(rootViewController: ViewController_WeatherAPI()) + let navigationController = UINavigationController(rootViewController: ViewController_TMDBAPI()) self.window?.rootViewController = navigationController // 4. self.window?.makeKeyAndVisible() diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/CurrentWeatherService.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/CurrentWeatherService.swift index ca7b5af..30828f8 100644 --- a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/CurrentWeatherService.swift +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/CurrentWeatherService.swift @@ -16,9 +16,9 @@ final class CurrentWeatherService { private init() {} func loadWeather(city: String, - completion: @escaping (NetworkResult) -> Void) { + completion: @escaping (NetworkResult) -> Void) { - let url = Config.weatherURL + "q=\(city)" + "&appid=" + Config.weatherAPI + let url = Config.weatherURL + "q=\(city)&appid=" + Config.weatherAPI let header: HTTPHeaders = ["Content-Type" : "application/json"] diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ImageCacheManager.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ImageCacheManager.swift new file mode 100644 index 0000000..fceacfd --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ImageCacheManager.swift @@ -0,0 +1,62 @@ +// +// ImageCacheManager.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/12. +// + +import UIKit + +enum ImageNetworkError: Error { + case `default` +} + +class ImageCacheManager { + static let shared = NSCache() + private init() { } + + static func getImage ( + _ url: String, + completion: @escaping (Swift.Result) -> Void + ) { + if url.isEmpty { completion(.failure(.default)) } + let cachedKey = NSString(string: url) + + if let cachedImage = ImageCacheManager.shared.object(forKey: cachedKey) { + completion(.success(cachedImage)) + } + + guard let url = URL(string: url) else { + completion(.failure(.default)) + return + } + + URLSession.shared.dataTask(with: url) { data, response, error in + DispatchQueue.main.async { + if let _ = error { + completion(.failure(.default)) + } + if let data = data, let image = UIImage(data: data) { + ImageCacheManager.shared.setObject(image, forKey: cachedKey) + completion(.success(image)) + } + } + } + .resume() + } +} + +extension UIImageView { + func getImageFromURL(_ url: String) { + let imageURL = "https://image.tmdb.org/t/p/original" + url + ImageCacheManager.getImage(imageURL) { result in + switch result { + case .failure(.default): + print("fail") + self.image = UIImage() + case .success(let image): + self.image = image + } + } + } +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieDataModel.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieDataModel.swift new file mode 100644 index 0000000..c08a284 --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieDataModel.swift @@ -0,0 +1,15 @@ +// +// MovieDataModel.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/12. +// + +import Foundation + +struct MovieDataModel { + let posterPath: String? + let title: String + let realizeDate: String + let movieRating: Double +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift index 0b7613c..9d5c47d 100644 --- a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift @@ -1,37 +1,49 @@ +// This file was generated from JSON Schema using quicktype, do not modify it directly. +// To parse the JSON, add this file to your project and do: // -// MovieInformation.swift -// 32th-Sopt-Seminar -// -// Created by kyun on 2023/05/12. -// +// let movieInformation = try? JSONDecoder().decode(MovieInformation.self, from: jsonData) import Foundation +// MARK: - MovieInformation struct MovieInformation: Codable { - let posterPath: String + let page: Int + let results: [Result] + let totalPages, totalResults: Int + + enum CodingKeys: String, CodingKey { + case page, results + case totalPages = "total_pages" + case totalResults = "total_results" + } +} + +// MARK: - Result +struct Result: Codable { let adult: Bool - let overview, releaseDate: String + let backdropPath: String? let genreIDS: [Int] let id: Int - let originalTitle, originalLanguage, title, backdropPath: String + let originalLanguage, originalTitle, overview: String let popularity: Double - let voteCount: Int + let posterPath: String? + let releaseDate, title: String let video: Bool let voteAverage: Double + let voteCount: Int enum CodingKeys: String, CodingKey { - case posterPath = "poster_path" - case adult, overview - case releaseDate = "release_date" + case adult + case backdropPath = "backdrop_path" case genreIDS = "genre_ids" case id - case originalTitle = "original_title" case originalLanguage = "original_language" - case title - case backdropPath = "backdrop_path" - case popularity - case voteCount = "vote_count" - case video + case originalTitle = "original_title" + case overview, popularity + case posterPath = "poster_path" + case releaseDate = "release_date" + case title, video case voteAverage = "vote_average" + case voteCount = "vote_count" } } diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift new file mode 100644 index 0000000..f7b227f --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift @@ -0,0 +1,64 @@ +// +// MovieInformationService.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/12. +// + +import Foundation + +import Alamofire + +final class MovieInformationService { + + static let get = MovieInformationService() + + private init() {} + + func loadMovieInformation(title: String, + completion: @escaping (NetworkResult) -> Void) { + + let url = Config.tmdbURL + title + + print(url) + + let header: HTTPHeaders = ["Content-Type" : "application/json"] + + let dataRequest = AF.request(url, method: .get, encoding: URLEncoding.default, headers: header) + + dataRequest.responseData { response in + switch response.result { + case .success: + guard let statusCode = response.response?.statusCode else { return } + guard let value = response.value else { return } + let networkResult = self.judgeStatus(by: statusCode, value) + completion(networkResult) + case .failure: + completion(.networkErr) + } + } + } + + private func judgeStatus(by statusCode: Int, _ data: Data) -> NetworkResult { + + switch statusCode { + case 200...299: + return isValidData(data: data) + case 400, 409: + return isValidData(data: data) + case 500: + return .serverErr + default: + return .networkErr + } + } + + private func isValidData(data: Data) -> NetworkResult { + + let decoder = JSONDecoder() + + guard let decodedData = try? decoder.decode(MovieInformation.self, from: data) else { return .pathErr } + + return .success(decodedData as Any) + } +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieTableViewCell.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieTableViewCell.swift new file mode 100644 index 0000000..1691ff6 --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieTableViewCell.swift @@ -0,0 +1,76 @@ +// +// MovieTableViewCell.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/12. +// + +import UIKit + +class MovieTableViewCell: UITableViewCell { + + private let posterImg = UIImageView().then { + $0.image = UIImage(named: "hypeBoy") + $0.makeRounded(radius: 8) + } + + private let titleLabel = UILabel().then { + $0.text = "제목입니다" + $0.textColor = .black + } + + private let releaseDateLabel = UILabel().then { + $0.text = "개봉일입니다" + $0.textColor = .black + } + + private let movieRatingLabel = UILabel().then { + $0.text = "평점입니다" + $0.textColor = .black + } + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + setLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func movieDataBind(movieDataModel: MovieDataModel) { + if let imageURL = movieDataModel.posterPath { + posterImg.getImageFromURL(imageURL) + } + titleLabel.text = movieDataModel.title + releaseDateLabel.text = movieDataModel.realizeDate + movieRatingLabel.text = "\(movieDataModel.movieRating)" + } + + func setLayout() { + addSubviews(posterImg, titleLabel, releaseDateLabel, movieRatingLabel) + + posterImg.snp.makeConstraints { + $0.leading.equalToSuperview().offset(10) + $0.centerY.equalToSuperview() + $0.height.equalTo(240) + $0.width.equalTo(160) + } + + titleLabel.snp.makeConstraints { + $0.trailing.equalToSuperview().inset(10) + $0.top.equalToSuperview().offset(50) + } + + releaseDateLabel.snp.makeConstraints { + $0.trailing.equalToSuperview().inset(10) + $0.top.equalTo(titleLabel.snp.bottom).offset(50) + } + + movieRatingLabel.snp.makeConstraints { + $0.trailing.equalToSuperview().inset(10) + $0.top.equalTo(releaseDateLabel.snp.bottom).offset(50) + } + } +} diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_TMDBAPI.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_TMDBAPI.swift new file mode 100644 index 0000000..1e4e08f --- /dev/null +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_TMDBAPI.swift @@ -0,0 +1,79 @@ +// +// ViewController_TMDBAPI.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/12. +// + +import UIKit + +import SnapKit +import Then + +class ViewController_TMDBAPI: UIViewController { + + private var movieArray: [MovieDataModel] = [] + + private lazy var movieTableView = UITableView().then { + $0.delegate = self + $0.dataSource = self + } + + override func viewDidLoad() { + super.viewDidLoad() + + registerCell() + loadMovieInformation() + setLayout() + } + + private func loadMovieInformation() { + + MovieInformationService.get.loadMovieInformation(title: "Jack+Reacher") { response in + switch response { + case .success(let data): + guard let data = data as? MovieInformation else { return } + self.movieArray = data.results.map { movie in + MovieDataModel(posterPath: movie.posterPath, title: movie.title, realizeDate: movie.releaseDate, movieRating: movie.voteAverage) + } + self.movieTableView.reloadData() + dump(data) + default: + return + } + } + } + + func registerCell() { + movieTableView.register(MovieTableViewCell.self, forCellReuseIdentifier: MovieTableViewCell.className) + } + + func setLayout() { + + view.addSubview(movieTableView) + + movieTableView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + } +} + +extension ViewController_TMDBAPI: UITableViewDelegate, UITableViewDataSource { + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + + return movieArray.count + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 300 + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + + guard let cell = tableView.dequeueReusableCell(withIdentifier: MovieTableViewCell.className, for: indexPath) as? MovieTableViewCell else { return UITableViewCell() } + + cell.movieDataBind(movieDataModel: self.movieArray[indexPath.row]) + return cell + } +} From 0ff8c27fb737fd40944639b642fa0800b4f9c5a5 Mon Sep 17 00:00:00 2001 From: ckkim817 Date: Fri, 12 May 2023 23:34:43 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=EC=98=88=EC=8B=9C=20Iron=20Man=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Fourth-Seminar/ImageCacheManager.swift | 82 +++++++++---------- .../Fourth-Seminar/MovieInformation.swift | 4 +- .../MovieInformationService.swift | 2 +- .../Fourth-Seminar/MovieTableViewCell.swift | 4 + .../ViewController_TMDBAPI.swift | 12 ++- 5 files changed, 56 insertions(+), 48 deletions(-) diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ImageCacheManager.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ImageCacheManager.swift index fceacfd..63c002f 100644 --- a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ImageCacheManager.swift +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ImageCacheManager.swift @@ -8,55 +8,55 @@ import UIKit enum ImageNetworkError: Error { - case `default` + case `default` } class ImageCacheManager { - static let shared = NSCache() - private init() { } - - static func getImage ( - _ url: String, - completion: @escaping (Swift.Result) -> Void - ) { - if url.isEmpty { completion(.failure(.default)) } - let cachedKey = NSString(string: url) - - if let cachedImage = ImageCacheManager.shared.object(forKey: cachedKey) { - completion(.success(cachedImage)) - } - - guard let url = URL(string: url) else { - completion(.failure(.default)) - return - } - - URLSession.shared.dataTask(with: url) { data, response, error in - DispatchQueue.main.async { - if let _ = error { - completion(.failure(.default)) + static let shared = NSCache() + private init() { } + + static func getImage ( + _ url: String, + completion: @escaping (Swift.Result) -> Void + ) { + if url.isEmpty { completion(.failure(.default)) } + let cachedKey = NSString(string: url) + + if let cachedImage = ImageCacheManager.shared.object(forKey: cachedKey) { + completion(.success(cachedImage)) + } + + guard let url = URL(string: url) else { + completion(.failure(.default)) + return } - if let data = data, let image = UIImage(data: data) { - ImageCacheManager.shared.setObject(image, forKey: cachedKey) - completion(.success(image)) + + URLSession.shared.dataTask(with: url) { data, response, error in + DispatchQueue.main.async { + if let _ = error { + completion(.failure(.default)) + } + if let data = data, let image = UIImage(data: data) { + ImageCacheManager.shared.setObject(image, forKey: cachedKey) + completion(.success(image)) + } + } } - } + .resume() } - .resume() - } } extension UIImageView { - func getImageFromURL(_ url: String) { - let imageURL = "https://image.tmdb.org/t/p/original" + url - ImageCacheManager.getImage(imageURL) { result in - switch result { - case .failure(.default): - print("fail") - self.image = UIImage() - case .success(let image): - self.image = image - } + func getImageFromURL(_ url: String) { + let imageURL = "https://image.tmdb.org/t/p/original" + url + ImageCacheManager.getImage(imageURL) { result in + switch result { + case .failure(.default): + print("fail") + self.image = UIImage() + case .success(let image): + self.image = image + } + } } - } } diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift index 9d5c47d..88b9cae 100644 --- a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift @@ -10,7 +10,7 @@ struct MovieInformation: Codable { let page: Int let results: [Result] let totalPages, totalResults: Int - + enum CodingKeys: String, CodingKey { case page, results case totalPages = "total_pages" @@ -31,7 +31,7 @@ struct Result: Codable { let video: Bool let voteAverage: Double let voteCount: Int - + enum CodingKeys: String, CodingKey { case adult case backdropPath = "backdrop_path" diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift index f7b227f..050324a 100644 --- a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift @@ -23,7 +23,7 @@ final class MovieInformationService { print(url) let header: HTTPHeaders = ["Content-Type" : "application/json"] - + let dataRequest = AF.request(url, method: .get, encoding: URLEncoding.default, headers: header) dataRequest.responseData { response in diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieTableViewCell.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieTableViewCell.swift index 1691ff6..275827d 100644 --- a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieTableViewCell.swift +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieTableViewCell.swift @@ -30,6 +30,7 @@ class MovieTableViewCell: UITableViewCell { } override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) setLayout() @@ -40,15 +41,18 @@ class MovieTableViewCell: UITableViewCell { } func movieDataBind(movieDataModel: MovieDataModel) { + if let imageURL = movieDataModel.posterPath { posterImg.getImageFromURL(imageURL) } + titleLabel.text = movieDataModel.title releaseDateLabel.text = movieDataModel.realizeDate movieRatingLabel.text = "\(movieDataModel.movieRating)" } func setLayout() { + addSubviews(posterImg, titleLabel, releaseDateLabel, movieRatingLabel) posterImg.snp.makeConstraints { diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_TMDBAPI.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_TMDBAPI.swift index 1e4e08f..72e3aa7 100644 --- a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_TMDBAPI.swift +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/ViewController_TMDBAPI.swift @@ -11,7 +11,7 @@ import SnapKit import Then class ViewController_TMDBAPI: UIViewController { - + private var movieArray: [MovieDataModel] = [] private lazy var movieTableView = UITableView().then { @@ -20,16 +20,17 @@ class ViewController_TMDBAPI: UIViewController { } override func viewDidLoad() { + super.viewDidLoad() - + registerCell() loadMovieInformation() setLayout() } - + private func loadMovieInformation() { - MovieInformationService.get.loadMovieInformation(title: "Jack+Reacher") { response in + MovieInformationService.get.loadMovieInformation(title: "Iron+Man") { response in switch response { case .success(let data): guard let data = data as? MovieInformation else { return } @@ -45,6 +46,7 @@ class ViewController_TMDBAPI: UIViewController { } func registerCell() { + movieTableView.register(MovieTableViewCell.self, forCellReuseIdentifier: MovieTableViewCell.className) } @@ -66,6 +68,7 @@ extension ViewController_TMDBAPI: UITableViewDelegate, UITableViewDataSource { } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 300 } @@ -74,6 +77,7 @@ extension ViewController_TMDBAPI: UITableViewDelegate, UITableViewDataSource { guard let cell = tableView.dequeueReusableCell(withIdentifier: MovieTableViewCell.className, for: indexPath) as? MovieTableViewCell else { return UITableViewCell() } cell.movieDataBind(movieDataModel: self.movieArray[indexPath.row]) + return cell } } From 4d75990d58141b3930e4f7bd646feb78b2c4355c Mon Sep 17 00:00:00 2001 From: ckkim817 Date: Sat, 13 May 2023 00:14:44 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=ED=92=80=EB=A6=AC=ED=80=98=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Fourth-Seminar/MovieInformation.swift | 10 +++++----- .../Fourth-Seminar/MovieInformationService.swift | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift index 88b9cae..e4c8b5e 100644 --- a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformation.swift @@ -1,11 +1,12 @@ -// This file was generated from JSON Schema using quicktype, do not modify it directly. -// To parse the JSON, add this file to your project and do: // -// let movieInformation = try? JSONDecoder().decode(MovieInformation.self, from: jsonData) +// MovieInformation.swift +// 32th-Sopt-Seminar +// +// Created by kyun on 2023/05/12. +// import Foundation -// MARK: - MovieInformation struct MovieInformation: Codable { let page: Int let results: [Result] @@ -18,7 +19,6 @@ struct MovieInformation: Codable { } } -// MARK: - Result struct Result: Codable { let adult: Bool let backdropPath: String? diff --git a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift index 050324a..3785285 100644 --- a/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift +++ b/32th-Sopt-Seminar/Presentation/32th-Sopt-Seminar/Fourth-Seminar/MovieInformationService.swift @@ -20,8 +20,6 @@ final class MovieInformationService { let url = Config.tmdbURL + title - print(url) - let header: HTTPHeaders = ["Content-Type" : "application/json"] let dataRequest = AF.request(url, method: .get, encoding: URLEncoding.default, headers: header)