From 294e8e933da2dd2bb6e42b6281b7995092f22e98 Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Fri, 8 Mar 2024 19:21:39 +0900 Subject: [PATCH 01/18] =?UTF-8?q?chore:=20MovieInfoSubdetail=20=ED=95=98?= =?UTF-8?q?=EC=9C=84=20DTO=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BoxOffice/Model/DTO/MovieDetailDTO.swift | 16 ++++++------- .../{Actor.swift => ActorDTO.swift} | 2 +- .../{Audit.swift => AuditDTO.swift} | 2 +- .../{Company.swift => CompanyDTO.swift} | 2 +- .../{Director.swift => DirectorDTO.swift} | 2 +- .../{Genre.swift => GenreDTO.swift} | 2 +- .../{Nation.swift => NationDTO.swift} | 2 +- .../{showType.swift => ShowTypeDTO.swift} | 2 +- .../{Staff.swift => StaffDTO.swift} | 2 +- BoxOffice/Network/Errors.swift | 13 ---------- BoxOffice/Network/HTTPMethod.swift | 8 +++++++ BoxOffice/Network/NetworkError.swift | 24 +++++++++++++++++++ ...343\204\264\343\205\207\343\204\271.swift" | 8 +++++++ 13 files changed, 56 insertions(+), 29 deletions(-) rename BoxOffice/Model/DTO/MovieInfoSubDetail/{Actor.swift => ActorDTO.swift} (92%) rename BoxOffice/Model/DTO/MovieInfoSubDetail/{Audit.swift => AuditDTO.swift} (90%) rename BoxOffice/Model/DTO/MovieInfoSubDetail/{Company.swift => CompanyDTO.swift} (93%) rename BoxOffice/Model/DTO/MovieInfoSubDetail/{Director.swift => DirectorDTO.swift} (89%) rename BoxOffice/Model/DTO/MovieInfoSubDetail/{Genre.swift => GenreDTO.swift} (86%) rename BoxOffice/Model/DTO/MovieInfoSubDetail/{Nation.swift => NationDTO.swift} (86%) rename BoxOffice/Model/DTO/MovieInfoSubDetail/{showType.swift => ShowTypeDTO.swift} (90%) rename BoxOffice/Model/DTO/MovieInfoSubDetail/{Staff.swift => StaffDTO.swift} (92%) delete mode 100644 BoxOffice/Network/Errors.swift create mode 100644 BoxOffice/Network/HTTPMethod.swift create mode 100644 BoxOffice/Network/NetworkError.swift create mode 100644 "BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" diff --git a/BoxOffice/Model/DTO/MovieDetailDTO.swift b/BoxOffice/Model/DTO/MovieDetailDTO.swift index c9f28201..d03a1677 100644 --- a/BoxOffice/Model/DTO/MovieDetailDTO.swift +++ b/BoxOffice/Model/DTO/MovieDetailDTO.swift @@ -29,14 +29,14 @@ extension MovieDetailDTO.MovieInfoDTO { let openDate: String let productionStatusName: String let typeName: String - let nations: [Nation] - let genres: [Genre] - let directors: [Director] - let actors: [Actor] - let showTypes: [ShowType] - let companys: [Company] - let audits: [Audit] - let staffs: [Staff] + let nations: [NationDTO] + let genres: [GenreDTO] + let directors: [DirectorDTO] + let actors: [ActorDTO] + let showTypes: [ShowTypeDTO] + let companys: [CompanyDTO] + let audits: [AuditDTO] + let staffs: [StaffDTO] } } diff --git a/BoxOffice/Model/DTO/MovieInfoSubDetail/Actor.swift b/BoxOffice/Model/DTO/MovieInfoSubDetail/ActorDTO.swift similarity index 92% rename from BoxOffice/Model/DTO/MovieInfoSubDetail/Actor.swift rename to BoxOffice/Model/DTO/MovieInfoSubDetail/ActorDTO.swift index 00f4cf31..67c1a9a7 100644 --- a/BoxOffice/Model/DTO/MovieInfoSubDetail/Actor.swift +++ b/BoxOffice/Model/DTO/MovieInfoSubDetail/ActorDTO.swift @@ -5,7 +5,7 @@ // Created by dopamint on 2/18/24. // -struct Actor: Decodable { +struct ActorDTO: Decodable { let peopleName: String let peopleNameInEnglish: String let cast: String diff --git a/BoxOffice/Model/DTO/MovieInfoSubDetail/Audit.swift b/BoxOffice/Model/DTO/MovieInfoSubDetail/AuditDTO.swift similarity index 90% rename from BoxOffice/Model/DTO/MovieInfoSubDetail/Audit.swift rename to BoxOffice/Model/DTO/MovieInfoSubDetail/AuditDTO.swift index 3d892f26..e186f1fe 100644 --- a/BoxOffice/Model/DTO/MovieInfoSubDetail/Audit.swift +++ b/BoxOffice/Model/DTO/MovieInfoSubDetail/AuditDTO.swift @@ -5,7 +5,7 @@ // Created by dopamint on 2/18/24. // -struct Audit: Decodable { +struct AuditDTO: Decodable { let auditNumber: String let watchGradeName: String diff --git a/BoxOffice/Model/DTO/MovieInfoSubDetail/Company.swift b/BoxOffice/Model/DTO/MovieInfoSubDetail/CompanyDTO.swift similarity index 93% rename from BoxOffice/Model/DTO/MovieInfoSubDetail/Company.swift rename to BoxOffice/Model/DTO/MovieInfoSubDetail/CompanyDTO.swift index 8ebee974..8c23eab9 100644 --- a/BoxOffice/Model/DTO/MovieInfoSubDetail/Company.swift +++ b/BoxOffice/Model/DTO/MovieInfoSubDetail/CompanyDTO.swift @@ -5,7 +5,7 @@ // Created by dopamint on 2/18/24. // -struct Company: Decodable { +struct CompanyDTO: Decodable { let companyCode: String let companyName: String let companyNameInEnglish: String diff --git a/BoxOffice/Model/DTO/MovieInfoSubDetail/Director.swift b/BoxOffice/Model/DTO/MovieInfoSubDetail/DirectorDTO.swift similarity index 89% rename from BoxOffice/Model/DTO/MovieInfoSubDetail/Director.swift rename to BoxOffice/Model/DTO/MovieInfoSubDetail/DirectorDTO.swift index 3df8f904..17718fbd 100644 --- a/BoxOffice/Model/DTO/MovieInfoSubDetail/Director.swift +++ b/BoxOffice/Model/DTO/MovieInfoSubDetail/DirectorDTO.swift @@ -5,7 +5,7 @@ // Created by dopamint on 2/18/24. // -struct Director: Decodable { +struct DirectorDTO: Decodable { let peopleName: String let peopleNameInEnglish: String diff --git a/BoxOffice/Model/DTO/MovieInfoSubDetail/Genre.swift b/BoxOffice/Model/DTO/MovieInfoSubDetail/GenreDTO.swift similarity index 86% rename from BoxOffice/Model/DTO/MovieInfoSubDetail/Genre.swift rename to BoxOffice/Model/DTO/MovieInfoSubDetail/GenreDTO.swift index 35ec7f4a..e3d99b58 100644 --- a/BoxOffice/Model/DTO/MovieInfoSubDetail/Genre.swift +++ b/BoxOffice/Model/DTO/MovieInfoSubDetail/GenreDTO.swift @@ -5,7 +5,7 @@ // Created by dopamint on 2/18/24. // -struct Genre: Decodable { +struct GenreDTO: Decodable { let genreName: String enum CodingKeys: String, CodingKey { diff --git a/BoxOffice/Model/DTO/MovieInfoSubDetail/Nation.swift b/BoxOffice/Model/DTO/MovieInfoSubDetail/NationDTO.swift similarity index 86% rename from BoxOffice/Model/DTO/MovieInfoSubDetail/Nation.swift rename to BoxOffice/Model/DTO/MovieInfoSubDetail/NationDTO.swift index c24e55d0..57ddda5e 100644 --- a/BoxOffice/Model/DTO/MovieInfoSubDetail/Nation.swift +++ b/BoxOffice/Model/DTO/MovieInfoSubDetail/NationDTO.swift @@ -5,7 +5,7 @@ // Created by dopamint on 2/18/24. // -struct Nation: Decodable { +struct NationDTO: Decodable { let nationName: String enum CodingKeys: String, CodingKey { diff --git a/BoxOffice/Model/DTO/MovieInfoSubDetail/showType.swift b/BoxOffice/Model/DTO/MovieInfoSubDetail/ShowTypeDTO.swift similarity index 90% rename from BoxOffice/Model/DTO/MovieInfoSubDetail/showType.swift rename to BoxOffice/Model/DTO/MovieInfoSubDetail/ShowTypeDTO.swift index def9a0de..5429d365 100644 --- a/BoxOffice/Model/DTO/MovieInfoSubDetail/showType.swift +++ b/BoxOffice/Model/DTO/MovieInfoSubDetail/ShowTypeDTO.swift @@ -5,7 +5,7 @@ // Created by dopamint on 2/18/24. // -struct ShowType: Decodable { +struct ShowTypeDTO: Decodable { let showTypeGroupName: String let showTypeName: String diff --git a/BoxOffice/Model/DTO/MovieInfoSubDetail/Staff.swift b/BoxOffice/Model/DTO/MovieInfoSubDetail/StaffDTO.swift similarity index 92% rename from BoxOffice/Model/DTO/MovieInfoSubDetail/Staff.swift rename to BoxOffice/Model/DTO/MovieInfoSubDetail/StaffDTO.swift index aa407cb7..5adf9dd0 100644 --- a/BoxOffice/Model/DTO/MovieInfoSubDetail/Staff.swift +++ b/BoxOffice/Model/DTO/MovieInfoSubDetail/StaffDTO.swift @@ -5,7 +5,7 @@ // Created by dopamint on 2/18/24. // -struct Staff: Decodable { +struct StaffDTO: Decodable { let peopleName: String let peopleNameInEnglish: String let staffRoleName: String diff --git a/BoxOffice/Network/Errors.swift b/BoxOffice/Network/Errors.swift deleted file mode 100644 index c7441441..00000000 --- a/BoxOffice/Network/Errors.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// Errors.swift -// BoxOffice -// -// Created by dopamint on 2/13/24. -// - -enum NetworkError: Error { - - case netWorkingError - case parseError - case dataError -} diff --git a/BoxOffice/Network/HTTPMethod.swift b/BoxOffice/Network/HTTPMethod.swift new file mode 100644 index 00000000..8e221695 --- /dev/null +++ b/BoxOffice/Network/HTTPMethod.swift @@ -0,0 +1,8 @@ +// +// HTTPMethod.swift +// BoxOffice +// +// Created by dopamint on 3/8/24. +// + +import Foundation diff --git a/BoxOffice/Network/NetworkError.swift b/BoxOffice/Network/NetworkError.swift new file mode 100644 index 00000000..bde1516d --- /dev/null +++ b/BoxOffice/Network/NetworkError.swift @@ -0,0 +1,24 @@ +// +// Errors.swift +// BoxOffice +// +// Created by dopamint on 2/13/24. +// + +enum NetworkError: Error { + + case netWorkingError + case parseError + case dataError + + func description() { + switch self { + case .netWorkingError: + print("네트워크 에러") + case .parseError: + print("파싱 에러") + case .dataError: + print("데이터 에러") + } + } +} diff --git "a/BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" "b/BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" new file mode 100644 index 00000000..2f4dca1d --- /dev/null +++ "b/BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" @@ -0,0 +1,8 @@ +// +// ㅁㄴㅇㄹ.swift +// BoxOffice +// +// Created by dopamint on 3/8/24. +// + +import Foundation From c87cdeb5966d71e71e75139c70337347be7b9356 Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Fri, 8 Mar 2024 19:22:25 +0900 Subject: [PATCH 02/18] =?UTF-8?q?feat:=20HTTPMethod=20enum=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BoxOffice/Network/HTTPMethod.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/BoxOffice/Network/HTTPMethod.swift b/BoxOffice/Network/HTTPMethod.swift index 8e221695..9d257b07 100644 --- a/BoxOffice/Network/HTTPMethod.swift +++ b/BoxOffice/Network/HTTPMethod.swift @@ -5,4 +5,10 @@ // Created by dopamint on 3/8/24. // -import Foundation +enum HTTPMethod: String { + case get = "GET" + case post = "POST" + case put = "PUT" + case patch = "PATCH" + case delete = "DELETE" +} From da5e705144c2187ecea57c02d89deba28d5ac01f Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Fri, 8 Mar 2024 19:23:25 +0900 Subject: [PATCH 03/18] refactor: parseJSON -> decode movieData -> data --- BoxOffice/Network/JSONParser.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/BoxOffice/Network/JSONParser.swift b/BoxOffice/Network/JSONParser.swift index 9daea7f3..390f40d1 100644 --- a/BoxOffice/Network/JSONParser.swift +++ b/BoxOffice/Network/JSONParser.swift @@ -9,13 +9,15 @@ import Foundation struct JSONParser{ - func parseJSON(_ movieData: Data, DTO: T.Type) -> T? { + func decode(_ data: Data, DTO: T.Type) -> T? { do { - let decodedData = try JSONDecoder().decode(T.self, from: movieData) + let decodedData = try JSONDecoder().decode(T.self, from: data) return decodedData } catch { - print("파싱 에러") + print("파싱 에러: \(NetworkError.parseError)") return nil } } } + + From 3bbaca9307894d252d345efccc4843885be21744 Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Fri, 8 Mar 2024 19:24:49 +0900 Subject: [PATCH 04/18] .. --- BoxOffice.xcodeproj/project.pbxproj | 90 ++++++++++--------- BoxOffice/MovieListViewController.swift | 20 +++-- BoxOffice/Network/NetworkAPI.swift | 2 +- BoxOffice/Network/NetworkError.swift | 11 --- BoxOffice/Network/Query.swift | 44 --------- ...343\204\264\343\205\207\343\204\271.swift" | 72 +++++++++++++++ NetworkManager.swift | 19 +++- 7 files changed, 156 insertions(+), 102 deletions(-) diff --git a/BoxOffice.xcodeproj/project.pbxproj b/BoxOffice.xcodeproj/project.pbxproj index ab928a0b..0a05e3f7 100644 --- a/BoxOffice.xcodeproj/project.pbxproj +++ b/BoxOffice.xcodeproj/project.pbxproj @@ -13,21 +13,23 @@ 63DF20F62970E1A0005DF7D1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 63DF20F42970E1A0005DF7D1 /* Main.storyboard */; }; 63DF20F82970E1A1005DF7D1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 63DF20F72970E1A1005DF7D1 /* Assets.xcassets */; }; 63DF20FB2970E1A1005DF7D1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 63DF20F92970E1A1005DF7D1 /* LaunchScreen.storyboard */; }; + 84B8A6F32B9AFBA900F33659 /* ㅁㄴㅇㄹ.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B8A6F22B9AFBA900F33659 /* ㅁㄴㅇㄹ.swift */; }; + 84B8A6F52B9AFC0800F33659 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B8A6F42B9AFC0800F33659 /* HTTPMethod.swift */; }; 84CCF7E82B8F6BE400CA2EDF /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7E72B8F6BE400CA2EDF /* NetworkManager.swift */; }; 84CCF7EA2B8F6BF800CA2EDF /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7E92B8F6BF800CA2EDF /* JSONParser.swift */; }; 84CCF7EC2B8F6C0000CA2EDF /* NetworkAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7EB2B8F6C0000CA2EDF /* NetworkAPI.swift */; }; - 84CCF7EE2B8F6C0900CA2EDF /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7ED2B8F6C0900CA2EDF /* Errors.swift */; }; + 84CCF7EE2B8F6C0900CA2EDF /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7ED2B8F6C0900CA2EDF /* NetworkError.swift */; }; 84CCF7F02B8F6C1300CA2EDF /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7EF2B8F6C1300CA2EDF /* Query.swift */; }; 84CCF7F42B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7F32B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift */; }; 84CCF7F62B8F6C4400CA2EDF /* MovieDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7F52B8F6C4400CA2EDF /* MovieDetailDTO.swift */; }; - 84CCF7F92B8F6C5F00CA2EDF /* Actor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7F82B8F6C5F00CA2EDF /* Actor.swift */; }; - 84CCF7FB2B8F6C6900CA2EDF /* Audit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7FA2B8F6C6900CA2EDF /* Audit.swift */; }; - 84CCF7FD2B8F6C7700CA2EDF /* Company.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7FC2B8F6C7700CA2EDF /* Company.swift */; }; - 84CCF7FF2B8F6C8900CA2EDF /* Director.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7FE2B8F6C8900CA2EDF /* Director.swift */; }; - 84CCF8012B8F6C9700CA2EDF /* Genre.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8002B8F6C9700CA2EDF /* Genre.swift */; }; - 84CCF8032B8F6CA000CA2EDF /* Nation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8022B8F6CA000CA2EDF /* Nation.swift */; }; - 84CCF8052B8F6CAE00CA2EDF /* showType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8042B8F6CAE00CA2EDF /* showType.swift */; }; - 84CCF8072B8F6CBD00CA2EDF /* Staff.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8062B8F6CBD00CA2EDF /* Staff.swift */; }; + 84CCF7F92B8F6C5F00CA2EDF /* ActorDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7F82B8F6C5F00CA2EDF /* ActorDTO.swift */; }; + 84CCF7FB2B8F6C6900CA2EDF /* AuditDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7FA2B8F6C6900CA2EDF /* AuditDTO.swift */; }; + 84CCF7FD2B8F6C7700CA2EDF /* CompanyDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7FC2B8F6C7700CA2EDF /* CompanyDTO.swift */; }; + 84CCF7FF2B8F6C8900CA2EDF /* DirectorDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7FE2B8F6C8900CA2EDF /* DirectorDTO.swift */; }; + 84CCF8012B8F6C9700CA2EDF /* GenreDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8002B8F6C9700CA2EDF /* GenreDTO.swift */; }; + 84CCF8032B8F6CA000CA2EDF /* NationDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8022B8F6CA000CA2EDF /* NationDTO.swift */; }; + 84CCF8052B8F6CAE00CA2EDF /* ShowTypeDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8042B8F6CAE00CA2EDF /* ShowTypeDTO.swift */; }; + 84CCF8072B8F6CBD00CA2EDF /* StaffDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8062B8F6CBD00CA2EDF /* StaffDTO.swift */; }; E4C414782B7DEE2100BB8860 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = E4C414772B7DEE2100BB8860 /* .swiftlint.yml */; }; /* End PBXBuildFile section */ @@ -49,23 +51,25 @@ 63DF20F72970E1A1005DF7D1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 63DF20FA2970E1A1005DF7D1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 63DF20FC2970E1A1005DF7D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 84CCF7E42B8F6B5F00CA2EDF /* BoxOffice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; name = BoxOffice.app; path = "/Users/admin/Desktop/sesac/프로젝트/ios-box-office/build/Debug-iphoneos/BoxOffice.app"; sourceTree = ""; }; - 84CCF7E52B8F6B5F00CA2EDF /* BoxOfficeUnitTest.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = BoxOfficeUnitTest.xctest; path = "/Users/admin/Desktop/sesac/프로젝트/ios-box-office/build/Debug/BoxOfficeUnitTest.xctest"; sourceTree = ""; }; + 84B8A6DD2B99BA2200F33659 /* BoxOffice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BoxOffice.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 84B8A6DE2B99BA2200F33659 /* BoxOfficeUnitTest.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BoxOfficeUnitTest.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 84B8A6F22B9AFBA900F33659 /* ㅁㄴㅇㄹ.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ㅁㄴㅇㄹ.swift"; sourceTree = ""; }; + 84B8A6F42B9AFC0800F33659 /* HTTPMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPMethod.swift; sourceTree = ""; }; 84CCF7E72B8F6BE400CA2EDF /* NetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = SOURCE_ROOT; }; 84CCF7E92B8F6BF800CA2EDF /* JSONParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONParser.swift; sourceTree = ""; }; 84CCF7EB2B8F6C0000CA2EDF /* NetworkAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkAPI.swift; sourceTree = ""; }; - 84CCF7ED2B8F6C0900CA2EDF /* Errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = ""; }; + 84CCF7ED2B8F6C0900CA2EDF /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = ""; }; 84CCF7EF2B8F6C1300CA2EDF /* Query.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Query.swift; sourceTree = ""; }; 84CCF7F32B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyBoxOfficeDTO.swift; sourceTree = ""; }; 84CCF7F52B8F6C4400CA2EDF /* MovieDetailDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieDetailDTO.swift; sourceTree = ""; }; - 84CCF7F82B8F6C5F00CA2EDF /* Actor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Actor.swift; sourceTree = ""; }; - 84CCF7FA2B8F6C6900CA2EDF /* Audit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Audit.swift; sourceTree = ""; }; - 84CCF7FC2B8F6C7700CA2EDF /* Company.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Company.swift; sourceTree = ""; }; - 84CCF7FE2B8F6C8900CA2EDF /* Director.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Director.swift; sourceTree = ""; }; - 84CCF8002B8F6C9700CA2EDF /* Genre.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Genre.swift; sourceTree = ""; }; - 84CCF8022B8F6CA000CA2EDF /* Nation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Nation.swift; sourceTree = ""; }; - 84CCF8042B8F6CAE00CA2EDF /* showType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = showType.swift; sourceTree = ""; }; - 84CCF8062B8F6CBD00CA2EDF /* Staff.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Staff.swift; sourceTree = ""; }; + 84CCF7F82B8F6C5F00CA2EDF /* ActorDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActorDTO.swift; sourceTree = ""; }; + 84CCF7FA2B8F6C6900CA2EDF /* AuditDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuditDTO.swift; sourceTree = ""; }; + 84CCF7FC2B8F6C7700CA2EDF /* CompanyDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanyDTO.swift; sourceTree = ""; }; + 84CCF7FE2B8F6C8900CA2EDF /* DirectorDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectorDTO.swift; sourceTree = ""; }; + 84CCF8002B8F6C9700CA2EDF /* GenreDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenreDTO.swift; sourceTree = ""; }; + 84CCF8022B8F6CA000CA2EDF /* NationDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NationDTO.swift; sourceTree = ""; }; + 84CCF8042B8F6CAE00CA2EDF /* ShowTypeDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowTypeDTO.swift; sourceTree = ""; }; + 84CCF8062B8F6CBD00CA2EDF /* StaffDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaffDTO.swift; sourceTree = ""; }; E4C414772B7DEE2100BB8860 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; /* End PBXFileReference section */ @@ -92,6 +96,8 @@ children = ( E4C414772B7DEE2100BB8860 /* .swiftlint.yml */, 63DF20ED2970E1A0005DF7D1 /* BoxOffice */, + 84B8A6DD2B99BA2200F33659 /* BoxOffice.app */, + 84B8A6DE2B99BA2200F33659 /* BoxOfficeUnitTest.xctest */, ); sourceTree = ""; }; @@ -116,8 +122,10 @@ 84CCF7E72B8F6BE400CA2EDF /* NetworkManager.swift */, 84CCF7E92B8F6BF800CA2EDF /* JSONParser.swift */, 84CCF7EB2B8F6C0000CA2EDF /* NetworkAPI.swift */, - 84CCF7ED2B8F6C0900CA2EDF /* Errors.swift */, + 84CCF7ED2B8F6C0900CA2EDF /* NetworkError.swift */, 84CCF7EF2B8F6C1300CA2EDF /* Query.swift */, + 84B8A6F42B9AFC0800F33659 /* HTTPMethod.swift */, + 84B8A6F22B9AFBA900F33659 /* ㅁㄴㅇㄹ.swift */, ); path = Network; sourceTree = ""; @@ -143,14 +151,14 @@ 84CCF7F72B8F6C5100CA2EDF /* MovieInfoSubDetail */ = { isa = PBXGroup; children = ( - 84CCF7F82B8F6C5F00CA2EDF /* Actor.swift */, - 84CCF7FA2B8F6C6900CA2EDF /* Audit.swift */, - 84CCF7FC2B8F6C7700CA2EDF /* Company.swift */, - 84CCF7FE2B8F6C8900CA2EDF /* Director.swift */, - 84CCF8042B8F6CAE00CA2EDF /* showType.swift */, - 84CCF8062B8F6CBD00CA2EDF /* Staff.swift */, - 84CCF8002B8F6C9700CA2EDF /* Genre.swift */, - 84CCF8022B8F6CA000CA2EDF /* Nation.swift */, + 84CCF7F82B8F6C5F00CA2EDF /* ActorDTO.swift */, + 84CCF7FA2B8F6C6900CA2EDF /* AuditDTO.swift */, + 84CCF7FC2B8F6C7700CA2EDF /* CompanyDTO.swift */, + 84CCF7FE2B8F6C8900CA2EDF /* DirectorDTO.swift */, + 84CCF8042B8F6CAE00CA2EDF /* ShowTypeDTO.swift */, + 84CCF8062B8F6CBD00CA2EDF /* StaffDTO.swift */, + 84CCF8002B8F6C9700CA2EDF /* GenreDTO.swift */, + 84CCF8022B8F6CA000CA2EDF /* NationDTO.swift */, ); path = MovieInfoSubDetail; sourceTree = ""; @@ -182,7 +190,7 @@ ); name = BoxOffice; productName = BoxOffice; - productReference = 84CCF7E42B8F6B5F00CA2EDF /* BoxOffice.app */; + productReference = 84B8A6DD2B99BA2200F33659 /* BoxOffice.app */; productType = "com.apple.product-type.application"; }; E4C414812B7E021400BB8860 /* BoxOfficeUnitTest */ = { @@ -200,7 +208,7 @@ ); name = BoxOfficeUnitTest; productName = BoxOfficeUnitTest; - productReference = 84CCF7E52B8F6B5F00CA2EDF /* BoxOfficeUnitTest.xctest */; + productReference = 84B8A6DE2B99BA2200F33659 /* BoxOfficeUnitTest.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ @@ -288,23 +296,25 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 84B8A6F32B9AFBA900F33659 /* ㅁㄴㅇㄹ.swift in Sources */, 63DF20F32970E1A0005DF7D1 /* MovieListViewController.swift in Sources */, 84CCF7F02B8F6C1300CA2EDF /* Query.swift in Sources */, 63DF20EF2970E1A0005DF7D1 /* AppDelegate.swift in Sources */, - 84CCF7F92B8F6C5F00CA2EDF /* Actor.swift in Sources */, + 84CCF7F92B8F6C5F00CA2EDF /* ActorDTO.swift in Sources */, 84CCF7F62B8F6C4400CA2EDF /* MovieDetailDTO.swift in Sources */, 84CCF7EA2B8F6BF800CA2EDF /* JSONParser.swift in Sources */, - 84CCF8032B8F6CA000CA2EDF /* Nation.swift in Sources */, + 84CCF8032B8F6CA000CA2EDF /* NationDTO.swift in Sources */, + 84B8A6F52B9AFC0800F33659 /* HTTPMethod.swift in Sources */, 84CCF7EC2B8F6C0000CA2EDF /* NetworkAPI.swift in Sources */, - 84CCF8012B8F6C9700CA2EDF /* Genre.swift in Sources */, - 84CCF7FF2B8F6C8900CA2EDF /* Director.swift in Sources */, + 84CCF8012B8F6C9700CA2EDF /* GenreDTO.swift in Sources */, + 84CCF7FF2B8F6C8900CA2EDF /* DirectorDTO.swift in Sources */, 84CCF7F42B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift in Sources */, - 84CCF7FB2B8F6C6900CA2EDF /* Audit.swift in Sources */, - 84CCF7EE2B8F6C0900CA2EDF /* Errors.swift in Sources */, - 84CCF8072B8F6CBD00CA2EDF /* Staff.swift in Sources */, + 84CCF7FB2B8F6C6900CA2EDF /* AuditDTO.swift in Sources */, + 84CCF7EE2B8F6C0900CA2EDF /* NetworkError.swift in Sources */, + 84CCF8072B8F6CBD00CA2EDF /* StaffDTO.swift in Sources */, 84CCF7E82B8F6BE400CA2EDF /* NetworkManager.swift in Sources */, - 84CCF8052B8F6CAE00CA2EDF /* showType.swift in Sources */, - 84CCF7FD2B8F6C7700CA2EDF /* Company.swift in Sources */, + 84CCF8052B8F6CAE00CA2EDF /* ShowTypeDTO.swift in Sources */, + 84CCF7FD2B8F6C7700CA2EDF /* CompanyDTO.swift in Sources */, 63DF20F12970E1A0005DF7D1 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/BoxOffice/MovieListViewController.swift b/BoxOffice/MovieListViewController.swift index 6132d740..e5b941fa 100644 --- a/BoxOffice/MovieListViewController.swift +++ b/BoxOffice/MovieListViewController.swift @@ -6,7 +6,7 @@ // import UIKit - +import OSLog final class MovieListViewController: UIViewController { private let networking = NetworkManager.shared @@ -14,8 +14,12 @@ final class MovieListViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - callDailyBoxOfficeAPI() +// callDailyBoxOfficeAPI() callMovieDetailAPI() + + os_log("네트워크 오류남", log: .network, type: .error) + os_log("네트워크 오류남", type: .error) + os_log("default") } private func callMovieDetailAPI() { @@ -24,11 +28,11 @@ final class MovieListViewController: UIViewController { switch result { case .success(let data): guard let data = data, - let decodedData = JSONParser().parseJSON(data as! Data, DTO: MovieDetailDTO.self) + let decodedData = JSONParser().decode(data as! Data, DTO: DailyBoxOfficeResultDTO.self) else { return } - print(decodedData.movieInfoResult.movieInfo.companys) + print(decodedData) case .failure(let error): print(error) } @@ -41,7 +45,7 @@ final class MovieListViewController: UIViewController { switch result { case .success(let data): guard let data = data, - let decodedData = JSONParser().parseJSON(data as! Data, DTO: DailyBoxOfficeResultDTO.self) + let decodedData = JSONParser().decode(data as! Data, DTO: DailyBoxOfficeResultDTO.self) else { return } @@ -52,3 +56,9 @@ final class MovieListViewController: UIViewController { } } } + +extension OSLog { + private static var subsystem = Bundle.main.bundleIdentifier! + + static let network = OSLog(subsystem: subsystem, category: "Network") +} diff --git a/BoxOffice/Network/NetworkAPI.swift b/BoxOffice/Network/NetworkAPI.swift index ca25f89a..937044c5 100644 --- a/BoxOffice/Network/NetworkAPI.swift +++ b/BoxOffice/Network/NetworkAPI.swift @@ -12,7 +12,7 @@ struct NetworkAPI { func buildDailyBoxOfficeAPI(targetDate: APIURLCompnents.QueryValues) -> URL? { return buildUrl(apiType: .dailyBoxOffice, query: targetDate).url } - + func buildMovieDetailAPI(movieCode: APIURLCompnents.QueryValues) -> URL? { return buildUrl(apiType: .movieDetail, query: movieCode).url } diff --git a/BoxOffice/Network/NetworkError.swift b/BoxOffice/Network/NetworkError.swift index bde1516d..c7441441 100644 --- a/BoxOffice/Network/NetworkError.swift +++ b/BoxOffice/Network/NetworkError.swift @@ -10,15 +10,4 @@ enum NetworkError: Error { case netWorkingError case parseError case dataError - - func description() { - switch self { - case .netWorkingError: - print("네트워크 에러") - case .parseError: - print("파싱 에러") - case .dataError: - print("데이터 에러") - } - } } diff --git a/BoxOffice/Network/Query.swift b/BoxOffice/Network/Query.swift index 4fb55edd..b69ea627 100644 --- a/BoxOffice/Network/Query.swift +++ b/BoxOffice/Network/Query.swift @@ -43,47 +43,3 @@ enum APIType: String { } } } - - - -//struct APIURLCompnents { -// static let schema = "https" -// static let host = "www.kobis.or.kr" -// static let basePath = "/kobisopenapi/webservice/rest/" -// static let boxOffice = "boxoffice/" -// static let movie = "movie/" -// static let APIKey = "23a93cbbbc8fdc2ae474716728465cca" -//} -// -//struct DailyBoxOfficeAPIQueries { -// enum QueryKeys: String { -// case itemPerPage -// case multiMovieYn -// case repNationCd -// case wideAreaCd -// } -// -// enum QueryValues: String { -// case targetDate = "20240228" -// } -//} -// -//struct MovieDetailAPIQueries { -// enum QueryValues: String { -// case movieCode = "20124079" -// } -//} -// -//enum APIType: String { -// case dailyBoxOffice = "targetDt" -// case movieDetail = "movieCd" -// -// func makePath() -> String { -// switch self { -// case .dailyBoxOffice: -// return APIURLCompnents.basePath + APIURLCompnents.boxOffice + "searchDailyBoxOfficeList.json" -// case .movieDetail: -// return APIURLCompnents.basePath + APIURLCompnents.movie + "searchMovieInfo.json" -// } -// } -//} diff --git "a/BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" "b/BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" index 2f4dca1d..ed958891 100644 --- "a/BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" +++ "b/BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" @@ -6,3 +6,75 @@ // import Foundation + +protocol TargetType { + + var method: HTTPMethod { get } + var path: String { get } + var parameters: RequestParameters { get } + var header: HeaderType { get } +} + +extension TargetType { + + var baseURL: String { + return NetworkEnvironment.baseURL + } + + private func asURL(_ url: String) throws -> URL { + guard let url = URL(string: url) + else { + throw NetworkError.invalidURL + } + + return url + } + + private func makeHeader(for request: URLRequest) -> URLRequest { + var request = request + + switch header { + case .basic: + request.setValue(ContentType.json.rawValue, + forHTTPHeaderField: HTTPHeaderField.contentType.rawValue) + } + + return request + } + + private func makeParameter(for request: URLRequest, with url: URL) throws -> URLRequest { + var request = request + + switch parameters { + case .query(let query): + let queryParams = query.map { URLQueryItem(name: $0.key, value: "\($0.value)") } + var components = URLComponents(string: url.appendingPathComponent(path).absoluteString) + components?.queryItems = queryParams + request.url = components?.url + + case .queryBody(let query, let body): + let queryParams = query.map { URLQueryItem(name: $0.key, value: "\($0.value)") } + var components = URLComponents(string: url.appendingPathComponent(path).absoluteString) + components?.queryItems = queryParams + request.url = components?.url + request.httpBody = try JSONSerialization.data(withJSONObject: body, options: []) + + case .requestBody(let body): + request.httpBody = try JSONSerialization.data(withJSONObject: body, options: []) + + case .requestPlain: + break + } + + return request + } + + func creatURLRequest() throws -> URLRequest { + let url = try asURL(baseURL) + var urlRequest = URLRequest(url: url.appendingPathComponent(path)) + urlRequest.httpMethod = method.rawValue + urlRequest = self.makeHeader(for: urlRequest) + + return try makeParameter(for: urlRequest, with: url) + } +} diff --git a/NetworkManager.swift b/NetworkManager.swift index 918ba9c7..d268f559 100644 --- a/NetworkManager.swift +++ b/NetworkManager.swift @@ -10,17 +10,32 @@ import Foundation class NetworkManager { static let shared = NetworkManager() - let networkAPI = NetworkAPI() + private let networkAPI = NetworkAPI() private init() {} typealias NetworkCompletion = (Result) -> Void +// func creatURLRequest(url: URL, ) throws -> URLRequest { +// let url = try asURL(baseURL) +// var urlRequest = URLRequest(url: url.appendingPathComponent(path)) +// urlRequest.httpMethod = method.rawValue +// urlRequest = self.makeHeader(for: urlRequest) +// +// return try makeParameter(for: urlRequest, with: url) +// } + func performRequest(with url: URL?, completion: @escaping (Result) -> Void) { guard let url else { return } let session = URLSession(configuration: .default) + var request = URLRequest(url: url) +// request.httpMethod = HTTPMethod +// request.addValue("application/json", forHTTPHeaderField: "Content-Type") +// request.addValue("application/json", forHTTPHeaderField: "Accept") +// request.httpBody = try JSONSerialization.data(withJSONObject: body, options: JSONSerialization.WritingOptions.prettyPrinted) + let task = session.dataTask(with: url) { data, response, error in print(url) guard error == nil else { @@ -41,3 +56,5 @@ class NetworkManager { task.resume() } } + + From 15a4c46bc10e0fa894a3e8cee9d2f5ed56f5bf8c Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Tue, 19 Mar 2024 19:22:41 +0900 Subject: [PATCH 05/18] =?UTF-8?q?feat:=20navigationController=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mainViewController를 rootView로 가지고 있는 navigationController --- BoxOffice/App/AppDelegate.swift | 9 ++- BoxOffice/App/SceneDelegate.swift | 38 ++++----- BoxOffice/Base.lproj/LaunchScreen.storyboard | 25 ------ BoxOffice/Base.lproj/Main.storyboard | 33 -------- BoxOffice/MovieListCollectionViewCell.swift | 12 +++ BoxOffice/Network/Errors/HTTPError.swift | 13 +++ .../Network/{ => Errors}/NetworkError.swift | 2 +- BoxOffice/Network/Errors/dateFormmater.swift | 8 ++ .../APIURLBuilder.swift" | 4 +- .../Query.swift" | 0 ...343\204\264\343\205\207\343\204\271.swift" | 80 ------------------- .../APICaller.swift" | 8 ++ BoxOffice/String+.swift | 8 ++ 13 files changed, 73 insertions(+), 167 deletions(-) delete mode 100644 BoxOffice/Base.lproj/LaunchScreen.storyboard delete mode 100644 BoxOffice/Base.lproj/Main.storyboard create mode 100644 BoxOffice/MovieListCollectionViewCell.swift create mode 100644 BoxOffice/Network/Errors/HTTPError.swift rename BoxOffice/Network/{ => Errors}/NetworkError.swift (85%) create mode 100644 BoxOffice/Network/Errors/dateFormmater.swift rename BoxOffice/Network/NetworkAPI.swift => "BoxOffice/Network/\341\204\206\341\205\250\343\205\221\343\205\241\341\204\206\341\205\256\341\206\267\343\205\216\343\204\267\343\204\261/APIURLBuilder.swift" (97%) rename BoxOffice/Network/Query.swift => "BoxOffice/Network/\341\204\206\341\205\250\343\205\221\343\205\241\341\204\206\341\205\256\341\206\267\343\205\216\343\204\267\343\204\261/Query.swift" (100%) delete mode 100644 "BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" create mode 100644 "BoxOffice/Network/\353\252\214\343\205\221\343\205\241\353\255\204\343\205\216\343\204\267\343\204\261/APICaller.swift" create mode 100644 BoxOffice/String+.swift diff --git a/BoxOffice/App/AppDelegate.swift b/BoxOffice/App/AppDelegate.swift index f321c71b..381239af 100644 --- a/BoxOffice/App/AppDelegate.swift +++ b/BoxOffice/App/AppDelegate.swift @@ -13,12 +13,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. + let appearance = UINavigationBarAppearance() + appearance.configureWithOpaqueBackground() + UINavigationBar.appearance().standardAppearance = appearance +// UINavigationBar.appearance().scrollEdgeAppearance = appearance 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. diff --git a/BoxOffice/App/SceneDelegate.swift b/BoxOffice/App/SceneDelegate.swift index 1ac597ee..a9b0b5c2 100644 --- a/BoxOffice/App/SceneDelegate.swift +++ b/BoxOffice/App/SceneDelegate.swift @@ -8,43 +8,35 @@ import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { - + var window: UIWindow? - - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - guard let _ = (scene as? UIWindowScene) else { return } + + func scene(_ scene: UIScene, + willConnectTo session: UISceneSession, + options connectionOptions: UIScene.ConnectionOptions) { + guard let windowScene = (scene as? UIWindowScene) else { return } + window = UIWindow(windowScene: windowScene) + let mainViewController = MovieListViewController() + let navigationController = UINavigationController(rootViewController: mainViewController) + window?.rootViewController = navigationController + navigationController.view.backgroundColor = .white +// window?.backgroundColor = .white + window?.makeKeyAndVisible() } - + func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). } - + func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). } func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. } func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. } diff --git a/BoxOffice/Base.lproj/LaunchScreen.storyboard b/BoxOffice/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e9329..00000000 --- a/BoxOffice/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/BoxOffice/Base.lproj/Main.storyboard b/BoxOffice/Base.lproj/Main.storyboard deleted file mode 100644 index 87ec70b5..00000000 --- a/BoxOffice/Base.lproj/Main.storyboard +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/BoxOffice/MovieListCollectionViewCell.swift b/BoxOffice/MovieListCollectionViewCell.swift new file mode 100644 index 00000000..4eed74e9 --- /dev/null +++ b/BoxOffice/MovieListCollectionViewCell.swift @@ -0,0 +1,12 @@ +// +// MovieListCollectionViewCell.swift +// BoxOffice +// +// Created by dopamint on 3/14/24. +// + +import UIKit + +class MovieListCollectionViewCell: UICollectionViewCell { + +} diff --git a/BoxOffice/Network/Errors/HTTPError.swift b/BoxOffice/Network/Errors/HTTPError.swift new file mode 100644 index 00000000..10b9b72d --- /dev/null +++ b/BoxOffice/Network/Errors/HTTPError.swift @@ -0,0 +1,13 @@ +// +// HTTPError.swift +// BoxOffice +// +// Created by dopamint on 3/8/24. +// + +enum HTTPError: Error { + case redirectionMessages(_ statusCode: Int, _ description: String) + case clientErrorResponses(_ statusCode: Int, _ description: String) + case serverErrorResponses(_ statusCode: Int, _ description: String) + case networkFailError(_ statusCode: Int) +} diff --git a/BoxOffice/Network/NetworkError.swift b/BoxOffice/Network/Errors/NetworkError.swift similarity index 85% rename from BoxOffice/Network/NetworkError.swift rename to BoxOffice/Network/Errors/NetworkError.swift index c7441441..a168ccb3 100644 --- a/BoxOffice/Network/NetworkError.swift +++ b/BoxOffice/Network/Errors/NetworkError.swift @@ -7,7 +7,7 @@ enum NetworkError: Error { - case netWorkingError + case responseError case parseError case dataError } diff --git a/BoxOffice/Network/Errors/dateFormmater.swift b/BoxOffice/Network/Errors/dateFormmater.swift new file mode 100644 index 00000000..7280f0cf --- /dev/null +++ b/BoxOffice/Network/Errors/dateFormmater.swift @@ -0,0 +1,8 @@ +// +// dateFormmater.swift +// BoxOffice +// +// Created by dopamint on 3/12/24. +// + +import Foundation diff --git a/BoxOffice/Network/NetworkAPI.swift "b/BoxOffice/Network/\341\204\206\341\205\250\343\205\221\343\205\241\341\204\206\341\205\256\341\206\267\343\205\216\343\204\267\343\204\261/APIURLBuilder.swift" similarity index 97% rename from BoxOffice/Network/NetworkAPI.swift rename to "BoxOffice/Network/\341\204\206\341\205\250\343\205\221\343\205\241\341\204\206\341\205\256\341\206\267\343\205\216\343\204\267\343\204\261/APIURLBuilder.swift" index 937044c5..e25486d7 100644 --- a/BoxOffice/Network/NetworkAPI.swift +++ "b/BoxOffice/Network/\341\204\206\341\205\250\343\205\221\343\205\241\341\204\206\341\205\256\341\206\267\343\205\216\343\204\267\343\204\261/APIURLBuilder.swift" @@ -7,7 +7,7 @@ import Foundation -struct NetworkAPI { +struct APIURLBuilder { func buildDailyBoxOfficeAPI(targetDate: APIURLCompnents.QueryValues) -> URL? { return buildUrl(apiType: .dailyBoxOffice, query: targetDate).url @@ -31,7 +31,7 @@ struct NetworkAPI { } } -extension NetworkAPI { +extension APIURLBuilder { func buildDailyBoxOfficeAPI(targetDate: APIURLCompnents.QueryValues, keys: APIURLCompnents.QueryKeys..., values: Any...) -> URL? { let dict: [APIURLCompnents.QueryKeys: Any] = zip(keys, values).reduce(into: [:]) { partialResult, now in partialResult[now.0] = now.1 diff --git a/BoxOffice/Network/Query.swift "b/BoxOffice/Network/\341\204\206\341\205\250\343\205\221\343\205\241\341\204\206\341\205\256\341\206\267\343\205\216\343\204\267\343\204\261/Query.swift" similarity index 100% rename from BoxOffice/Network/Query.swift rename to "BoxOffice/Network/\341\204\206\341\205\250\343\205\221\343\205\241\341\204\206\341\205\256\341\206\267\343\205\216\343\204\267\343\204\261/Query.swift" diff --git "a/BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" "b/BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" deleted file mode 100644 index ed958891..00000000 --- "a/BoxOffice/Network/\343\205\201\343\204\264\343\205\207\343\204\271.swift" +++ /dev/null @@ -1,80 +0,0 @@ -// -// ㅁㄴㅇㄹ.swift -// BoxOffice -// -// Created by dopamint on 3/8/24. -// - -import Foundation - -protocol TargetType { - - var method: HTTPMethod { get } - var path: String { get } - var parameters: RequestParameters { get } - var header: HeaderType { get } -} - -extension TargetType { - - var baseURL: String { - return NetworkEnvironment.baseURL - } - - private func asURL(_ url: String) throws -> URL { - guard let url = URL(string: url) - else { - throw NetworkError.invalidURL - } - - return url - } - - private func makeHeader(for request: URLRequest) -> URLRequest { - var request = request - - switch header { - case .basic: - request.setValue(ContentType.json.rawValue, - forHTTPHeaderField: HTTPHeaderField.contentType.rawValue) - } - - return request - } - - private func makeParameter(for request: URLRequest, with url: URL) throws -> URLRequest { - var request = request - - switch parameters { - case .query(let query): - let queryParams = query.map { URLQueryItem(name: $0.key, value: "\($0.value)") } - var components = URLComponents(string: url.appendingPathComponent(path).absoluteString) - components?.queryItems = queryParams - request.url = components?.url - - case .queryBody(let query, let body): - let queryParams = query.map { URLQueryItem(name: $0.key, value: "\($0.value)") } - var components = URLComponents(string: url.appendingPathComponent(path).absoluteString) - components?.queryItems = queryParams - request.url = components?.url - request.httpBody = try JSONSerialization.data(withJSONObject: body, options: []) - - case .requestBody(let body): - request.httpBody = try JSONSerialization.data(withJSONObject: body, options: []) - - case .requestPlain: - break - } - - return request - } - - func creatURLRequest() throws -> URLRequest { - let url = try asURL(baseURL) - var urlRequest = URLRequest(url: url.appendingPathComponent(path)) - urlRequest.httpMethod = method.rawValue - urlRequest = self.makeHeader(for: urlRequest) - - return try makeParameter(for: urlRequest, with: url) - } -} diff --git "a/BoxOffice/Network/\353\252\214\343\205\221\343\205\241\353\255\204\343\205\216\343\204\267\343\204\261/APICaller.swift" "b/BoxOffice/Network/\353\252\214\343\205\221\343\205\241\353\255\204\343\205\216\343\204\267\343\204\261/APICaller.swift" new file mode 100644 index 00000000..eec64ddf --- /dev/null +++ "b/BoxOffice/Network/\353\252\214\343\205\221\343\205\241\353\255\204\343\205\216\343\204\267\343\204\261/APICaller.swift" @@ -0,0 +1,8 @@ +// +// APICaller.swift +// BoxOffice +// +// Created by dopamint on 3/8/24. +// + +import Foundation diff --git a/BoxOffice/String+.swift b/BoxOffice/String+.swift new file mode 100644 index 00000000..be0de274 --- /dev/null +++ b/BoxOffice/String+.swift @@ -0,0 +1,8 @@ +// +// String+.swift +// BoxOffice +// +// Created by dopamint on 3/19/24. +// + +import Foundation From 0e7d1a087e3c057a17b0b7eefd8a92f2e84d77ae Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Tue, 19 Mar 2024 19:23:21 +0900 Subject: [PATCH 06/18] refactor: DailyBoxOfficeResultDTO -> DailyBoxOfficeDTO --- BoxOffice/Model/DTO/DailyBoxOfficeDTO.swift | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/BoxOffice/Model/DTO/DailyBoxOfficeDTO.swift b/BoxOffice/Model/DTO/DailyBoxOfficeDTO.swift index b9e87e55..4ad7bbf8 100644 --- a/BoxOffice/Model/DTO/DailyBoxOfficeDTO.swift +++ b/BoxOffice/Model/DTO/DailyBoxOfficeDTO.swift @@ -7,20 +7,19 @@ import Foundation -struct DailyBoxOfficeResultDTO: Decodable { +struct DailyBoxOfficeDTO: Decodable { let boxOfficeResult: BoxOfficeDTO } -extension DailyBoxOfficeResultDTO { +extension DailyBoxOfficeDTO { struct BoxOfficeDTO: Decodable { let boxOfficeType: String let dateRange: String let dailyBoxOfficeList: [MovieInfo]? } - } -extension DailyBoxOfficeResultDTO.BoxOfficeDTO { +extension DailyBoxOfficeDTO.BoxOfficeDTO { enum CodingKeys: String, CodingKey { case dateRange = "showRange" case boxOfficeType = "boxofficeType" @@ -28,7 +27,7 @@ extension DailyBoxOfficeResultDTO.BoxOfficeDTO { } } -extension DailyBoxOfficeResultDTO.BoxOfficeDTO { +extension DailyBoxOfficeDTO.BoxOfficeDTO { struct MovieInfo: Decodable { let rankNumber: String let rank: String @@ -51,7 +50,7 @@ extension DailyBoxOfficeResultDTO.BoxOfficeDTO { } } -extension DailyBoxOfficeResultDTO.BoxOfficeDTO.MovieInfo { +extension DailyBoxOfficeDTO.BoxOfficeDTO.MovieInfo { enum CodingKeys: String, CodingKey { case rankNumber = "rnum" case rank From f8a2d670aad26229934be9c6f4f4ea4a8373f406 Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Tue, 19 Mar 2024 19:26:12 +0900 Subject: [PATCH 07/18] refactor: networkAPI -> APIURLBuilder --- .../Network/APIManager/APIURLBuilder.swift | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 BoxOffice/Network/APIManager/APIURLBuilder.swift diff --git a/BoxOffice/Network/APIManager/APIURLBuilder.swift b/BoxOffice/Network/APIManager/APIURLBuilder.swift new file mode 100644 index 00000000..26efac38 --- /dev/null +++ b/BoxOffice/Network/APIManager/APIURLBuilder.swift @@ -0,0 +1,58 @@ +// +// NetworkAPI.swift +// BoxOffice +// +// Created by dopamint on 2/17/24. +// + +import Foundation + +struct APIURLBuilder { + + func buildDailyBoxOfficeAPI(targetDate: String) -> URL? { + return buildUrl(apiType: .dailyBoxOffice, query: targetDate).url + } + + func buildMovieDetailAPI(movieCode: String) -> URL? { + return buildUrl(apiType: .movieDetail, query: movieCode).url + } + + private func buildUrl(apiType: APIType, query: String) -> URLComponents { + var components = URLComponents() + components.scheme = APIURLCompnents.schema + components.host = APIURLCompnents.host + components.path = apiType.makePath() + + components.queryItems = [ + URLQueryItem(name: "key", value: APIURLCompnents.QueryValues.APIKey.rawValue), + URLQueryItem(name: apiType.rawValue , value: query) + ] + return components + } +} + +extension APIURLBuilder { + func buildDailyBoxOfficeAPI(targetDate: APIURLCompnents.QueryValues, keys: APIURLCompnents.QueryKeys..., values: Any...) -> URL? { + let dict: [APIURLCompnents.QueryKeys: Any] = zip(keys, values).reduce(into: [:]) { partialResult, now in + partialResult[now.0] = now.1 + } + return buildUrl(apiType: .dailyBoxOffice, requiredQuery: targetDate, queries: dict).url + } + + private func buildUrl(apiType: APIType, requiredQuery: APIURLCompnents.QueryValues, queries: [APIURLCompnents.QueryKeys: Any]) -> URLComponents { + var components = URLComponents() + components.scheme = APIURLCompnents.schema + components.host = APIURLCompnents.host + components.path = apiType.makePath() + + components.queryItems = [ + URLQueryItem(name: "key", value: APIURLCompnents.QueryValues.APIKey.rawValue), + URLQueryItem(name: apiType.rawValue , value: requiredQuery.rawValue) + ] + queries.forEach { (key: APIURLCompnents.QueryKeys, value: Any) in + components.queryItems?.append(URLQueryItem(name: key.rawValue, + value: value as? String)) + } + return components + } +} From 0236792048a82d732a56873c3a014dc33800029e Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Tue, 19 Mar 2024 19:27:08 +0900 Subject: [PATCH 08/18] =?UTF-8?q?feat:=20Date.yesterday=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BoxOffice/Network/APIManager/Query.swift | 70 ++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 BoxOffice/Network/APIManager/Query.swift diff --git a/BoxOffice/Network/APIManager/Query.swift b/BoxOffice/Network/APIManager/Query.swift new file mode 100644 index 00000000..ee5fef45 --- /dev/null +++ b/BoxOffice/Network/APIManager/Query.swift @@ -0,0 +1,70 @@ +// +// query.swift +// BoxOffice +// +// Created by dopamint on 2/17/24. +// + +import Foundation + + + +struct APIURLCompnents { + + static let schema = "https" + static let host = "www.kobis.or.kr" + static let basePath = "/kobisopenapi/webservice/rest/" + static let boxOffice = "boxoffice/" + static let movie = "movie/" + + enum QueryKeys: String { + + case itemPerPage + case multiMovieYn + case repNationCd + case wideAreaCd + } + + enum QueryValues: String { + + case APIKey = "23a93cbbbc8fdc2ae474716728465cca" + static var targetDate = Date().yesterday + case movieCode = "20124079" + } +} + +extension Date { + var yesterday: String? { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyyMMdd" + let today = Date() + let timezone = TimeZone.autoupdatingCurrent + let secondsFromGMT = timezone.secondsFromGMT(for: today) + let localizedDate = today.addingTimeInterval(TimeInterval(secondsFromGMT)) + let yesterday = Calendar(identifier: .gregorian).date(byAdding: .day, value: -2, to: localizedDate) + guard let dateString = dateFormatter.string(for: yesterday) else { + return "알 수 없는 날짜" + } + + print(secondsFromGMT) + print(localizedDate) + print(yesterday as Any) + print(dateString) + return dateString + } +} + +enum APIType: String { + + case dailyBoxOffice = "targetDt" + case movieDetail = "movieCd" + + func makePath() -> String { + switch self { + case .dailyBoxOffice: + return APIURLCompnents.basePath + APIURLCompnents.boxOffice + "searchDailyBoxOfficeList.json" + case .movieDetail: + return APIURLCompnents.basePath + APIURLCompnents.movie + "searchMovieInfo.json" + } + } +} From 806962dd0c12ca57793a3ee88fda5bfa88901770 Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Tue, 19 Mar 2024 19:27:31 +0900 Subject: [PATCH 09/18] =?UTF-8?q?feat:=20dateFormmater=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BoxOffice/Network/Errors/dateFormmater.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/BoxOffice/Network/Errors/dateFormmater.swift b/BoxOffice/Network/Errors/dateFormmater.swift index 7280f0cf..22b4ab83 100644 --- a/BoxOffice/Network/Errors/dateFormmater.swift +++ b/BoxOffice/Network/Errors/dateFormmater.swift @@ -6,3 +6,20 @@ // import Foundation + +struct Formatter { + func formatting() -> String? { + let dateFormatter = DateFormatter() + + let today = Date() + let timezone = TimeZone.autoupdatingCurrent + let secondsFromGMT = timezone.secondsFromGMT(for: today) + let localizedDate = today.addingTimeInterval(TimeInterval(secondsFromGMT)) + + let yesterday = Calendar(identifier: .gregorian).date(byAdding: .day, value: -2, to: localizedDate) + + let dateString = dateFormatter.string(for: yesterday) + + return dateString + } +} From 16e56ba60f286adbf9fffd79c0c7a399b66ca423 Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Tue, 19 Mar 2024 19:29:34 +0900 Subject: [PATCH 10/18] =?UTF-8?q?chore:=20=EC=9E=90=EC=9E=98=ED=95=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BoxOffice.xcodeproj/project.pbxproj | 77 +++++++++---------- BoxOffice/Info.plist | 2 - BoxOffice/Network/Errors/NetworkError.swift | 1 - BoxOffice/Network/JSONParser.swift | 4 +- .../APICaller.swift" | 8 -- 5 files changed, 40 insertions(+), 52 deletions(-) delete mode 100644 "BoxOffice/Network/\353\252\214\343\205\221\343\205\241\353\255\204\343\205\216\343\204\267\343\204\261/APICaller.swift" diff --git a/BoxOffice.xcodeproj/project.pbxproj b/BoxOffice.xcodeproj/project.pbxproj index 0a05e3f7..2e5ec1fe 100644 --- a/BoxOffice.xcodeproj/project.pbxproj +++ b/BoxOffice.xcodeproj/project.pbxproj @@ -10,14 +10,13 @@ 63DF20EF2970E1A0005DF7D1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63DF20EE2970E1A0005DF7D1 /* AppDelegate.swift */; }; 63DF20F12970E1A0005DF7D1 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63DF20F02970E1A0005DF7D1 /* SceneDelegate.swift */; }; 63DF20F32970E1A0005DF7D1 /* MovieListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63DF20F22970E1A0005DF7D1 /* MovieListViewController.swift */; }; - 63DF20F62970E1A0005DF7D1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 63DF20F42970E1A0005DF7D1 /* Main.storyboard */; }; 63DF20F82970E1A1005DF7D1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 63DF20F72970E1A1005DF7D1 /* Assets.xcassets */; }; - 63DF20FB2970E1A1005DF7D1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 63DF20F92970E1A1005DF7D1 /* LaunchScreen.storyboard */; }; - 84B8A6F32B9AFBA900F33659 /* ㅁㄴㅇㄹ.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B8A6F22B9AFBA900F33659 /* ㅁㄴㅇㄹ.swift */; }; + 8494905D2BA9837B00628DBB /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8494905C2BA9837B00628DBB /* String+.swift */; }; 84B8A6F52B9AFC0800F33659 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B8A6F42B9AFC0800F33659 /* HTTPMethod.swift */; }; + 84B8A6F72B9B26E200F33659 /* HTTPError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B8A6F62B9B26E200F33659 /* HTTPError.swift */; }; 84CCF7E82B8F6BE400CA2EDF /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7E72B8F6BE400CA2EDF /* NetworkManager.swift */; }; 84CCF7EA2B8F6BF800CA2EDF /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7E92B8F6BF800CA2EDF /* JSONParser.swift */; }; - 84CCF7EC2B8F6C0000CA2EDF /* NetworkAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7EB2B8F6C0000CA2EDF /* NetworkAPI.swift */; }; + 84CCF7EC2B8F6C0000CA2EDF /* APIURLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7EB2B8F6C0000CA2EDF /* APIURLBuilder.swift */; }; 84CCF7EE2B8F6C0900CA2EDF /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7ED2B8F6C0900CA2EDF /* NetworkError.swift */; }; 84CCF7F02B8F6C1300CA2EDF /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7EF2B8F6C1300CA2EDF /* Query.swift */; }; 84CCF7F42B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7F32B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift */; }; @@ -30,6 +29,8 @@ 84CCF8032B8F6CA000CA2EDF /* NationDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8022B8F6CA000CA2EDF /* NationDTO.swift */; }; 84CCF8052B8F6CAE00CA2EDF /* ShowTypeDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8042B8F6CAE00CA2EDF /* ShowTypeDTO.swift */; }; 84CCF8072B8F6CBD00CA2EDF /* StaffDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8062B8F6CBD00CA2EDF /* StaffDTO.swift */; }; + 84DFC3792BA02FCD00E1F04D /* dateFormmater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DFC3782BA02FCD00E1F04D /* dateFormmater.swift */; }; + 84DFC37D2BA29AEC00E1F04D /* MovieListCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DFC37C2BA29AEC00E1F04D /* MovieListCollectionViewCell.swift */; }; E4C414782B7DEE2100BB8860 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = E4C414772B7DEE2100BB8860 /* .swiftlint.yml */; }; /* End PBXBuildFile section */ @@ -47,17 +48,16 @@ 63DF20EE2970E1A0005DF7D1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 63DF20F02970E1A0005DF7D1 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 63DF20F22970E1A0005DF7D1 /* MovieListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieListViewController.swift; sourceTree = ""; }; - 63DF20F52970E1A0005DF7D1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 63DF20F72970E1A1005DF7D1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 63DF20FA2970E1A1005DF7D1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 63DF20FC2970E1A1005DF7D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 8494905C2BA9837B00628DBB /* String+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+.swift"; sourceTree = ""; }; 84B8A6DD2B99BA2200F33659 /* BoxOffice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BoxOffice.app; sourceTree = BUILT_PRODUCTS_DIR; }; 84B8A6DE2B99BA2200F33659 /* BoxOfficeUnitTest.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BoxOfficeUnitTest.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 84B8A6F22B9AFBA900F33659 /* ㅁㄴㅇㄹ.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ㅁㄴㅇㄹ.swift"; sourceTree = ""; }; 84B8A6F42B9AFC0800F33659 /* HTTPMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPMethod.swift; sourceTree = ""; }; + 84B8A6F62B9B26E200F33659 /* HTTPError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPError.swift; sourceTree = ""; }; 84CCF7E72B8F6BE400CA2EDF /* NetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = SOURCE_ROOT; }; 84CCF7E92B8F6BF800CA2EDF /* JSONParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONParser.swift; sourceTree = ""; }; - 84CCF7EB2B8F6C0000CA2EDF /* NetworkAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkAPI.swift; sourceTree = ""; }; + 84CCF7EB2B8F6C0000CA2EDF /* APIURLBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIURLBuilder.swift; sourceTree = ""; }; 84CCF7ED2B8F6C0900CA2EDF /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = ""; }; 84CCF7EF2B8F6C1300CA2EDF /* Query.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Query.swift; sourceTree = ""; }; 84CCF7F32B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyBoxOfficeDTO.swift; sourceTree = ""; }; @@ -70,6 +70,8 @@ 84CCF8022B8F6CA000CA2EDF /* NationDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NationDTO.swift; sourceTree = ""; }; 84CCF8042B8F6CAE00CA2EDF /* ShowTypeDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowTypeDTO.swift; sourceTree = ""; }; 84CCF8062B8F6CBD00CA2EDF /* StaffDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaffDTO.swift; sourceTree = ""; }; + 84DFC3782BA02FCD00E1F04D /* dateFormmater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dateFormmater.swift; sourceTree = ""; }; + 84DFC37C2BA29AEC00E1F04D /* MovieListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieListCollectionViewCell.swift; sourceTree = ""; }; E4C414772B7DEE2100BB8860 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; /* End PBXFileReference section */ @@ -106,26 +108,43 @@ children = ( 84CCF8082B8F6CE000CA2EDF /* App */, 63DF20F22970E1A0005DF7D1 /* MovieListViewController.swift */, + 84DFC37C2BA29AEC00E1F04D /* MovieListCollectionViewCell.swift */, + 8494905C2BA9837B00628DBB /* String+.swift */, 84CCF7F12B8F6C2700CA2EDF /* Model */, 84CCF7E62B8F6BDA00CA2EDF /* Network */, - 63DF20F42970E1A0005DF7D1 /* Main.storyboard */, 63DF20F72970E1A1005DF7D1 /* Assets.xcassets */, - 63DF20F92970E1A1005DF7D1 /* LaunchScreen.storyboard */, 63DF20FC2970E1A1005DF7D1 /* Info.plist */, ); path = BoxOffice; sourceTree = ""; }; + 84B8A6F82B9B392000F33659 /* Errors */ = { + isa = PBXGroup; + children = ( + 84B8A6F62B9B26E200F33659 /* HTTPError.swift */, + 84CCF7ED2B8F6C0900CA2EDF /* NetworkError.swift */, + 84DFC3782BA02FCD00E1F04D /* dateFormmater.swift */, + ); + path = Errors; + sourceTree = ""; + }; + 84B8A6F92B9B3CE200F33659 /* APIManager */ = { + isa = PBXGroup; + children = ( + 84CCF7EB2B8F6C0000CA2EDF /* APIURLBuilder.swift */, + 84CCF7EF2B8F6C1300CA2EDF /* Query.swift */, + ); + path = APIManager; + sourceTree = ""; + }; 84CCF7E62B8F6BDA00CA2EDF /* Network */ = { isa = PBXGroup; children = ( 84CCF7E72B8F6BE400CA2EDF /* NetworkManager.swift */, + 84B8A6F92B9B3CE200F33659 /* APIManager */, 84CCF7E92B8F6BF800CA2EDF /* JSONParser.swift */, - 84CCF7EB2B8F6C0000CA2EDF /* NetworkAPI.swift */, - 84CCF7ED2B8F6C0900CA2EDF /* NetworkError.swift */, - 84CCF7EF2B8F6C1300CA2EDF /* Query.swift */, 84B8A6F42B9AFC0800F33659 /* HTTPMethod.swift */, - 84B8A6F22B9AFBA900F33659 /* ㅁㄴㅇㄹ.swift */, + 84B8A6F82B9B392000F33659 /* Errors */, ); path = Network; sourceTree = ""; @@ -255,9 +274,7 @@ buildActionMask = 2147483647; files = ( E4C414782B7DEE2100BB8860 /* .swiftlint.yml in Resources */, - 63DF20FB2970E1A1005DF7D1 /* LaunchScreen.storyboard in Resources */, 63DF20F82970E1A1005DF7D1 /* Assets.xcassets in Resources */, - 63DF20F62970E1A0005DF7D1 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -296,7 +313,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 84B8A6F32B9AFBA900F33659 /* ㅁㄴㅇㄹ.swift in Sources */, 63DF20F32970E1A0005DF7D1 /* MovieListViewController.swift in Sources */, 84CCF7F02B8F6C1300CA2EDF /* Query.swift in Sources */, 63DF20EF2970E1A0005DF7D1 /* AppDelegate.swift in Sources */, @@ -304,14 +320,18 @@ 84CCF7F62B8F6C4400CA2EDF /* MovieDetailDTO.swift in Sources */, 84CCF7EA2B8F6BF800CA2EDF /* JSONParser.swift in Sources */, 84CCF8032B8F6CA000CA2EDF /* NationDTO.swift in Sources */, + 84DFC3792BA02FCD00E1F04D /* dateFormmater.swift in Sources */, + 84DFC37D2BA29AEC00E1F04D /* MovieListCollectionViewCell.swift in Sources */, 84B8A6F52B9AFC0800F33659 /* HTTPMethod.swift in Sources */, - 84CCF7EC2B8F6C0000CA2EDF /* NetworkAPI.swift in Sources */, + 8494905D2BA9837B00628DBB /* String+.swift in Sources */, + 84CCF7EC2B8F6C0000CA2EDF /* APIURLBuilder.swift in Sources */, 84CCF8012B8F6C9700CA2EDF /* GenreDTO.swift in Sources */, 84CCF7FF2B8F6C8900CA2EDF /* DirectorDTO.swift in Sources */, 84CCF7F42B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift in Sources */, 84CCF7FB2B8F6C6900CA2EDF /* AuditDTO.swift in Sources */, 84CCF7EE2B8F6C0900CA2EDF /* NetworkError.swift in Sources */, 84CCF8072B8F6CBD00CA2EDF /* StaffDTO.swift in Sources */, + 84B8A6F72B9B26E200F33659 /* HTTPError.swift in Sources */, 84CCF7E82B8F6BE400CA2EDF /* NetworkManager.swift in Sources */, 84CCF8052B8F6CAE00CA2EDF /* ShowTypeDTO.swift in Sources */, 84CCF7FD2B8F6C7700CA2EDF /* CompanyDTO.swift in Sources */, @@ -336,25 +356,6 @@ }; /* End PBXTargetDependency section */ -/* Begin PBXVariantGroup section */ - 63DF20F42970E1A0005DF7D1 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 63DF20F52970E1A0005DF7D1 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 63DF20F92970E1A1005DF7D1 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 63DF20FA2970E1A1005DF7D1 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - /* Begin XCBuildConfiguration section */ 63DF20FD2970E1A1005DF7D1 /* Debug */ = { isa = XCBuildConfiguration; @@ -481,7 +482,6 @@ INFOPLIST_FILE = BoxOffice/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; IPHONEOS_DEPLOYMENT_TARGET = 13.0; @@ -509,7 +509,6 @@ INFOPLIST_FILE = BoxOffice/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; IPHONEOS_DEPLOYMENT_TARGET = 13.0; diff --git a/BoxOffice/Info.plist b/BoxOffice/Info.plist index dd3c9afd..0eb786dc 100644 --- a/BoxOffice/Info.plist +++ b/BoxOffice/Info.plist @@ -15,8 +15,6 @@ Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main diff --git a/BoxOffice/Network/Errors/NetworkError.swift b/BoxOffice/Network/Errors/NetworkError.swift index a168ccb3..6ec17cf4 100644 --- a/BoxOffice/Network/Errors/NetworkError.swift +++ b/BoxOffice/Network/Errors/NetworkError.swift @@ -6,7 +6,6 @@ // enum NetworkError: Error { - case responseError case parseError case dataError diff --git a/BoxOffice/Network/JSONParser.swift b/BoxOffice/Network/JSONParser.swift index 390f40d1..ac29eebd 100644 --- a/BoxOffice/Network/JSONParser.swift +++ b/BoxOffice/Network/JSONParser.swift @@ -7,14 +7,14 @@ import Foundation -struct JSONParser{ +struct JSONParser { func decode(_ data: Data, DTO: T.Type) -> T? { do { let decodedData = try JSONDecoder().decode(T.self, from: data) return decodedData } catch { - print("파싱 에러: \(NetworkError.parseError)") + print(NetworkError.parseError) return nil } } diff --git "a/BoxOffice/Network/\353\252\214\343\205\221\343\205\241\353\255\204\343\205\216\343\204\267\343\204\261/APICaller.swift" "b/BoxOffice/Network/\353\252\214\343\205\221\343\205\241\353\255\204\343\205\216\343\204\267\343\204\261/APICaller.swift" deleted file mode 100644 index eec64ddf..00000000 --- "a/BoxOffice/Network/\353\252\214\343\205\221\343\205\241\353\255\204\343\205\216\343\204\267\343\204\261/APICaller.swift" +++ /dev/null @@ -1,8 +0,0 @@ -// -// APICaller.swift -// BoxOffice -// -// Created by dopamint on 3/8/24. -// - -import Foundation From c4f26d824395ef92b143d8eb5631f821a3e0d814 Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Tue, 19 Mar 2024 19:30:32 +0900 Subject: [PATCH 11/18] =?UTF-8?q?refactor:=20performRequest=20async=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit completoinHandler 에서 swift cocurrency로 --- NetworkManager.swift | 75 +++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/NetworkManager.swift b/NetworkManager.swift index d268f559..1b02a3b8 100644 --- a/NetworkManager.swift +++ b/NetworkManager.swift @@ -8,53 +8,50 @@ import Foundation class NetworkManager { - + static let shared = NetworkManager() - private let networkAPI = NetworkAPI() private init() {} - typealias NetworkCompletion = (Result) -> Void - -// func creatURLRequest(url: URL, ) throws -> URLRequest { -// let url = try asURL(baseURL) -// var urlRequest = URLRequest(url: url.appendingPathComponent(path)) -// urlRequest.httpMethod = method.rawValue -// urlRequest = self.makeHeader(for: urlRequest) -// -// return try makeParameter(for: urlRequest, with: url) -// } - - func performRequest(with url: URL?, completion: @escaping (Result) -> Void) { + func performRequest(with url: URL?) async throws -> Data { guard let url else { - return + throw NetworkError.dataError } let session = URLSession(configuration: .default) - var request = URLRequest(url: url) -// request.httpMethod = HTTPMethod -// request.addValue("application/json", forHTTPHeaderField: "Content-Type") -// request.addValue("application/json", forHTTPHeaderField: "Accept") -// request.httpBody = try JSONSerialization.data(withJSONObject: body, options: JSONSerialization.WritingOptions.prettyPrinted) + let request = makeRequest(with: url, method: .get, headers: nil) + + let (data, response) = try await session.data(for: request) - let task = session.dataTask(with: url) { data, response, error in - print(url) - guard error == nil else { - print("네트워크 에러") - completion(.failure(.netWorkingError)) - return - } - guard let safeData = data else { - completion(.failure(.dataError)) - return - } - guard let response = response as? HTTPURLResponse, (200 ..< 299) ~= response.statusCode else { - completion(.failure(.netWorkingError)) - return - } - completion(.success(safeData)) + guard let statusCode = (response as? HTTPURLResponse)?.statusCode else { + throw NetworkError.responseError + } + guard (200 ..< 299) ~= statusCode else { + throw responseVerify(with: response as! HTTPURLResponse) + } + return data + } + + func makeRequest(with url: URL, method: HTTPMethod, headers: [String: String]?) -> URLRequest { + var request = URLRequest(url: url) + request.httpMethod = method.rawValue + + headers?.forEach { key, value in + request.addValue(value, forHTTPHeaderField: key) + } + return request + } + + private func responseVerify(with HTTPResponse: HTTPURLResponse) -> Error { + switch HTTPResponse.statusCode { + case (300...399): + return HTTPError.redirectionMessages(HTTPResponse.statusCode, HTTPResponse.debugDescription) + case (400...499): + return HTTPError.clientErrorResponses(HTTPResponse.statusCode, HTTPResponse.debugDescription) + case (500...599): + return HTTPError.serverErrorResponses(HTTPResponse.statusCode, HTTPResponse.debugDescription) + default: + return HTTPError.networkFailError(HTTPResponse.statusCode) } - task.resume() } } - - + From 6aab401d5eccac506ebb1f268dc5bbaa66ab772a Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Tue, 19 Mar 2024 19:31:01 +0900 Subject: [PATCH 12/18] =?UTF-8?q?feat:=20String.formatNumberString=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BoxOffice/String+.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/BoxOffice/String+.swift b/BoxOffice/String+.swift index be0de274..0e82ecce 100644 --- a/BoxOffice/String+.swift +++ b/BoxOffice/String+.swift @@ -6,3 +6,18 @@ // import Foundation + +extension String { + func formatNumberString() -> String { + let formatter = NumberFormatter() + formatter.numberStyle = .decimal + formatter.locale = Locale.current + + guard let number = Double(self), + let result = formatter.string(from: NSNumber(value: number)) + else { + return "" + } + return result + } +} From 4fde8761a733d4d808d2ed7ff2c192f22af563ad Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Tue, 19 Mar 2024 19:33:56 +0900 Subject: [PATCH 13/18] =?UTF-8?q?feat:=20MovieListViewController=ED=95=98?= =?UTF-8?q?=EC=9C=84=20=EB=B7=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit collectionVIew, activityIndicator, refreshContr --- BoxOffice/MovieListViewController.swift | 154 +++++++++++++++++------- 1 file changed, 112 insertions(+), 42 deletions(-) diff --git a/BoxOffice/MovieListViewController.swift b/BoxOffice/MovieListViewController.swift index e5b941fa..4b7e03ce 100644 --- a/BoxOffice/MovieListViewController.swift +++ b/BoxOffice/MovieListViewController.swift @@ -4,61 +4,131 @@ // // Created by kjs on 13/01/23. // - +import SwiftUI import UIKit -import OSLog + final class MovieListViewController: UIViewController { - private let networking = NetworkManager.shared - private let networkAPI = NetworkAPI() + private let networkManager = NetworkManager.shared + private var boxOfficeDataArray:[DailyBoxOfficeDTO.BoxOfficeDTO.MovieInfo] = [] + let apiBuilder = APIURLBuilder() + + private let collectionView: UICollectionView = { + let layout = UICollectionViewFlowLayout() + let CV = UICollectionView(frame: .zero, collectionViewLayout: layout) + return CV + }() + + lazy var activityIndicator: UIActivityIndicatorView = { + let activityIndicator = UIActivityIndicatorView() + activityIndicator.frame = CGRect(x: 0, y: 0, width: 50, height: 50) + activityIndicator.center = self.view.center + activityIndicator.hidesWhenStopped = false + activityIndicator.style = .large + activityIndicator.startAnimating() + return activityIndicator + }() + + private lazy var refreshControl: UIRefreshControl = { + let refreshControl = UIRefreshControl() + refreshControl.addTarget(self, action: #selector(reload), for: .valueChanged) + + return refreshControl + + }() override func viewDidLoad() { super.viewDidLoad() -// callDailyBoxOfficeAPI() - callMovieDetailAPI() - - os_log("네트워크 오류남", log: .network, type: .error) - os_log("네트워크 오류남", type: .error) - os_log("default") - } - - private func callMovieDetailAPI() { - let url = networkAPI.buildMovieDetailAPI(movieCode: .movieCode) - networking.performRequest(with: url) { result in - switch result { - case .success(let data): - guard let data = data, - let decodedData = JSONParser().decode(data as! Data, DTO: DailyBoxOfficeResultDTO.self) - else { - return - } - print(decodedData) - case .failure(let error): - print(error) + title = Date().yesterday + + collectionView.dataSource = self + collectionView.delegate = self + collectionView.refreshControl = refreshControl + setupCollectionView() + view.addSubview(activityIndicator) + + Task { + let data = try await networkManager.performRequest(with: apiBuilder.buildDailyBoxOfficeAPI(targetDate: APIURLCompnents.QueryValues.targetDate ?? "")) + + guard let DTO = JSONParser().decode(data, DTO: DailyBoxOfficeDTO.self), + let boxOfficeList = DTO.boxOfficeResult.dailyBoxOfficeList + else { + return } + + boxOfficeDataArray = boxOfficeList + collectionView.reloadData() + activityIndicator.isHidden = true } } - private func callDailyBoxOfficeAPI() { - let url = networkAPI.buildDailyBoxOfficeAPI(targetDate: .targetDate, keys: .itemPerPage, values: "2") - networking.performRequest(with: url) { result in - switch result { - case .success(let data): - guard let data = data, - let decodedData = JSONParser().decode(data as! Data, DTO: DailyBoxOfficeResultDTO.self) - else { - return - } - print(decodedData,"\n -------------------------") - case .failure(let error): - print(error) - } + @objc + func reload() { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { + self.collectionView.reloadData() + self.refreshControl.endRefreshing() } } + + private func setupCollectionView() { + collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell") + collectionView.register(MovieListCollectionViewCell.self, forCellWithReuseIdentifier: "MovieListCollectionViewCell") + + view.addSubview(collectionView) + collectionView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), + collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), + collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + ]) + } } -extension OSLog { - private static var subsystem = Bundle.main.bundleIdentifier! +extension MovieListViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MovieListCollectionViewCell", for: indexPath) as? MovieListCollectionViewCell else { + fatalError("fatalError") + } + cell.configureCell(with: boxOfficeDataArray[indexPath.row]) + cell.addSubview(MovieListCollectionViewCell()) + return cell + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + boxOfficeDataArray.count + } - static let network = OSLog(subsystem: subsystem, category: "Network") + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + + let width = collectionView.frame.width + return CGSize(width: width, height: 100) + } + + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + 0 + } } + + + +//import SwiftUI +//struct ViewControllerRepresentable: UIViewControllerRepresentable { +// +// // update +// func updateUIViewController(_ uiViewController: UIViewController, context: Context){ +// +// } +// // makeui +// @available(iOS 13.0, *) +// func makeUIViewController(context: Context) -> UIViewController { +// MovieListViewController() +// } +//} +// +//struct ViewController_Previews: PreviewProvider { +// static var previews: some View{ +// ViewControllerRepresentable().previewDisplayName("아이폰 15프로") +// } +//} + From 808a567eb1050107a1cb04e03b38cd075baca585 Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Tue, 19 Mar 2024 19:34:14 +0900 Subject: [PATCH 14/18] =?UTF-8?q?feat:=20MovieListCollectionViewCell=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BoxOffice/MovieListCollectionViewCell.swift | 142 ++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/BoxOffice/MovieListCollectionViewCell.swift b/BoxOffice/MovieListCollectionViewCell.swift index 4eed74e9..9b50089d 100644 --- a/BoxOffice/MovieListCollectionViewCell.swift +++ b/BoxOffice/MovieListCollectionViewCell.swift @@ -9,4 +9,146 @@ import UIKit class MovieListCollectionViewCell: UICollectionViewCell { + static let identifier = "MovieListCollectionViewCell" + + private let rankLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = UIFont.systemFont(ofSize: 40, weight: .semibold) + return label + }() + + private let rankChangeLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + let attributedString = NSMutableAttributedString(string: "순위변경") + label.font = UIFont.systemFont(ofSize: 14) + label.baselineAdjustment = .alignCenters + return label + }() + + private let movieTitleLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = UIFont.systemFont(ofSize: 25, weight: .semibold) + return label + }() + + private let audienceLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = UIFont.systemFont(ofSize: 16) + label.numberOfLines = 0 + return label + }() + + private lazy var rankStackView: UIStackView = { + let stackView = UIStackView() + stackView.addSubview(rankLabel) + stackView.addSubview(rankChangeLabel) + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.axis = .vertical + stackView.alignment = .center + stackView.distribution = .fill + + return stackView + }() + + private lazy var movieTitleStackView: UIStackView = { + let stackView = UIStackView(arrangedSubviews: [movieTitleLabel, audienceLabel]) + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.axis = .vertical + stackView.spacing = 5 + return stackView + }() + + private lazy var accessoryButton: UIButton = { + let button = UIButton(type: .custom) + button.translatesAutoresizingMaskIntoConstraints = false + button.setImage(UIImage(systemName: "chevron.right"), for: .normal) + button.tintColor = .gray + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + configureBorder() + setupUI() + + } + required init?(coder: NSCoder) { + super.init(coder: coder) + } +} + +extension MovieListCollectionViewCell { + + private func configureBorder() { + layer.borderWidth = 0.2 + layer.borderColor = UIColor.lightGray.cgColor + } + private func setupUI() { + contentView.addSubview(rankStackView) + contentView.addSubview(movieTitleStackView) + contentView.addSubview(accessoryButton) + + setupRankStackViewConstraint() + setupMovieTitleStackViewConstraint() + setupCellAccessoryButtonConstraint() + } + + private func setupRankStackViewConstraint() { + NSLayoutConstraint.activate([ + rankStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 1), + rankStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 1), + rankStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5), + rankStackView.widthAnchor.constraint(equalToConstant: 60), + rankLabel.centerXAnchor.constraint(equalTo: rankStackView.centerXAnchor), + rankChangeLabel.centerXAnchor.constraint(equalTo: rankStackView.centerXAnchor), + rankLabel.topAnchor.constraint(equalTo: rankStackView.topAnchor, constant: 10), + rankChangeLabel.topAnchor.constraint(equalTo: rankLabel.bottomAnchor) + ]) + } + + private func setupMovieTitleStackViewConstraint() { + NSLayoutConstraint.activate([ + movieTitleStackView.leadingAnchor.constraint(equalTo: rankStackView.trailingAnchor, constant: 30), + movieTitleStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16) + ]) + } + + private func setupCellAccessoryButtonConstraint() { + NSLayoutConstraint.activate([ + accessoryButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20), + accessoryButton.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 40), + accessoryButton.widthAnchor.constraint(equalToConstant: 20), + ]) + } + + func configureCell(with movieInfo: DailyBoxOfficeDTO.BoxOfficeDTO.MovieInfo) { + rankLabel.text = movieInfo.rank + rankChangeLabel.text = movieInfo.rankChanges + movieTitleLabel.text = movieInfo.movieName + audienceLabel.text = "오늘 :\(movieInfo.audienceCount.formatNumberString())명 / 총 :\( movieInfo.audienceAccumulated.formatNumberString())명" + + if movieInfo.rankOldAndNew == "NEW" { + rankChangeLabel.text = "신작" + return + } + + if let rankChangeValue = Int(movieInfo.rankChanges) { + if rankChangeValue > 0 { + rankChangeLabel.text = "▲ \(movieInfo.rankChanges)" + rankChangeLabel.textColor = .red + } else if rankChangeValue < 0 { + rankChangeLabel.text = "▼ \(movieInfo.rankChanges)" + rankChangeLabel.textColor = .blue + } else { + rankChangeLabel.text = "-" + rankChangeLabel.textColor = .black + } + } + } + } From a2959797e1101f4575a9735502e421a351739360 Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Wed, 20 Mar 2024 11:48:50 +0900 Subject: [PATCH 15/18] =?UTF-8?q?refactor:=20yesterday=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EB=A1=9C=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BoxOffice/App/AppDelegate.swift | 3 -- BoxOffice/App/SceneDelegate.swift | 1 - BoxOffice/Extension/Date+.swift | 35 +++++++++++++++++++ BoxOffice/{ => Extension}/String+.swift | 2 -- .../{Query.swift => APIURLCompnents.swift} | 23 ------------ BoxOffice/Network/Errors/dateFormmater.swift | 25 ------------- 6 files changed, 35 insertions(+), 54 deletions(-) create mode 100644 BoxOffice/Extension/Date+.swift rename BoxOffice/{ => Extension}/String+.swift (89%) rename BoxOffice/Network/APIManager/{Query.swift => APIURLCompnents.swift} (59%) delete mode 100644 BoxOffice/Network/Errors/dateFormmater.swift diff --git a/BoxOffice/App/AppDelegate.swift b/BoxOffice/App/AppDelegate.swift index 381239af..382d84c5 100644 --- a/BoxOffice/App/AppDelegate.swift +++ b/BoxOffice/App/AppDelegate.swift @@ -10,13 +10,10 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let appearance = UINavigationBarAppearance() appearance.configureWithOpaqueBackground() UINavigationBar.appearance().standardAppearance = appearance -// UINavigationBar.appearance().scrollEdgeAppearance = appearance return true } diff --git a/BoxOffice/App/SceneDelegate.swift b/BoxOffice/App/SceneDelegate.swift index a9b0b5c2..f287aa56 100644 --- a/BoxOffice/App/SceneDelegate.swift +++ b/BoxOffice/App/SceneDelegate.swift @@ -20,7 +20,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { let navigationController = UINavigationController(rootViewController: mainViewController) window?.rootViewController = navigationController navigationController.view.backgroundColor = .white -// window?.backgroundColor = .white window?.makeKeyAndVisible() } diff --git a/BoxOffice/Extension/Date+.swift b/BoxOffice/Extension/Date+.swift new file mode 100644 index 00000000..53af9bbd --- /dev/null +++ b/BoxOffice/Extension/Date+.swift @@ -0,0 +1,35 @@ +// +// Date+.swift +// BoxOffice +// +// Created by dopamint on 3/19/24. +// + +import Foundation + +extension Date { + var yesterday: String { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyyMMdd" + let today = Date() + let timezone = TimeZone.autoupdatingCurrent + let secondsFromGMT = timezone.secondsFromGMT(for: today) + let localizedDate = today.addingTimeInterval(TimeInterval(secondsFromGMT)) + let yesterday = Calendar(identifier: .gregorian).date(byAdding: .day, value: -2, to: localizedDate) + guard let dateString = dateFormatter.string(for: yesterday) else { + return "알 수 없는 날짜" + } + return dateString + } + + func addHyphen(dateString: String) -> String? { + let inputFormatter = DateFormatter() + inputFormatter.dateFormat = "yyyyMMdd" + if let date = inputFormatter.date(from: dateString) { + let outputFormatter = DateFormatter() + outputFormatter.dateFormat = "yyyy-MM-dd" + return outputFormatter.string(from: date) + } + return nil + } +} diff --git a/BoxOffice/String+.swift b/BoxOffice/Extension/String+.swift similarity index 89% rename from BoxOffice/String+.swift rename to BoxOffice/Extension/String+.swift index 0e82ecce..2c8c56e0 100644 --- a/BoxOffice/String+.swift +++ b/BoxOffice/Extension/String+.swift @@ -11,8 +11,6 @@ extension String { func formatNumberString() -> String { let formatter = NumberFormatter() formatter.numberStyle = .decimal - formatter.locale = Locale.current - guard let number = Double(self), let result = formatter.string(from: NSNumber(value: number)) else { diff --git a/BoxOffice/Network/APIManager/Query.swift b/BoxOffice/Network/APIManager/APIURLCompnents.swift similarity index 59% rename from BoxOffice/Network/APIManager/Query.swift rename to BoxOffice/Network/APIManager/APIURLCompnents.swift index ee5fef45..f12ef770 100644 --- a/BoxOffice/Network/APIManager/Query.swift +++ b/BoxOffice/Network/APIManager/APIURLCompnents.swift @@ -7,8 +7,6 @@ import Foundation - - struct APIURLCompnents { static let schema = "https" @@ -33,27 +31,6 @@ struct APIURLCompnents { } } -extension Date { - var yesterday: String? { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyyMMdd" - let today = Date() - let timezone = TimeZone.autoupdatingCurrent - let secondsFromGMT = timezone.secondsFromGMT(for: today) - let localizedDate = today.addingTimeInterval(TimeInterval(secondsFromGMT)) - let yesterday = Calendar(identifier: .gregorian).date(byAdding: .day, value: -2, to: localizedDate) - guard let dateString = dateFormatter.string(for: yesterday) else { - return "알 수 없는 날짜" - } - - print(secondsFromGMT) - print(localizedDate) - print(yesterday as Any) - print(dateString) - return dateString - } -} - enum APIType: String { case dailyBoxOffice = "targetDt" diff --git a/BoxOffice/Network/Errors/dateFormmater.swift b/BoxOffice/Network/Errors/dateFormmater.swift deleted file mode 100644 index 22b4ab83..00000000 --- a/BoxOffice/Network/Errors/dateFormmater.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// dateFormmater.swift -// BoxOffice -// -// Created by dopamint on 3/12/24. -// - -import Foundation - -struct Formatter { - func formatting() -> String? { - let dateFormatter = DateFormatter() - - let today = Date() - let timezone = TimeZone.autoupdatingCurrent - let secondsFromGMT = timezone.secondsFromGMT(for: today) - let localizedDate = today.addingTimeInterval(TimeInterval(secondsFromGMT)) - - let yesterday = Calendar(identifier: .gregorian).date(byAdding: .day, value: -2, to: localizedDate) - - let dateString = dateFormatter.string(for: yesterday) - - return dateString - } -} From 51c62470472e82161cd91ac69dfe51700f61664d Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Wed, 20 Mar 2024 11:49:54 +0900 Subject: [PATCH 16/18] =?UTF-8?q?refactor:=20yesterday=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EB=A1=9C=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BoxOffice/Extension/Date+.swift | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/BoxOffice/Extension/Date+.swift b/BoxOffice/Extension/Date+.swift index 53af9bbd..b296e6e6 100644 --- a/BoxOffice/Extension/Date+.swift +++ b/BoxOffice/Extension/Date+.swift @@ -8,28 +8,20 @@ import Foundation extension Date { - var yesterday: String { + static let yyyyMMdd = "yyyyMMdd" + static let yyyyMMddHyphen = "yyyy-MM-dd" + + func yesterday(format: String) -> String { let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyyMMdd" + dateFormatter.dateFormat = format let today = Date() let timezone = TimeZone.autoupdatingCurrent let secondsFromGMT = timezone.secondsFromGMT(for: today) let localizedDate = today.addingTimeInterval(TimeInterval(secondsFromGMT)) - let yesterday = Calendar(identifier: .gregorian).date(byAdding: .day, value: -2, to: localizedDate) + let yesterday = Calendar(identifier: .gregorian).date(byAdding: .day, value: -1, to: localizedDate) guard let dateString = dateFormatter.string(for: yesterday) else { return "알 수 없는 날짜" } return dateString } - - func addHyphen(dateString: String) -> String? { - let inputFormatter = DateFormatter() - inputFormatter.dateFormat = "yyyyMMdd" - if let date = inputFormatter.date(from: dateString) { - let outputFormatter = DateFormatter() - outputFormatter.dateFormat = "yyyy-MM-dd" - return outputFormatter.string(from: date) - } - return nil - } } From 4bb1ce77aa4c5d140fd7e85327c15b5916d9f70d Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Wed, 20 Mar 2024 11:50:21 +0900 Subject: [PATCH 17/18] =?UTF-8?q?chore:=20=EC=9E=90=EC=9E=98=ED=95=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BoxOffice.xcodeproj/project.pbxproj | 26 ++++--- BoxOffice/MovieListCollectionViewCell.swift | 11 ++- BoxOffice/MovieListViewController.swift | 71 ++++++------------- .../Network/APIManager/APIURLBuilder.swift | 6 +- .../Network/APIManager/APIURLCompnents.swift | 2 +- BoxOffice/Network/Errors/NetworkError.swift | 4 +- NetworkManager.swift | 13 ++-- 7 files changed, 57 insertions(+), 76 deletions(-) diff --git a/BoxOffice.xcodeproj/project.pbxproj b/BoxOffice.xcodeproj/project.pbxproj index 2e5ec1fe..950495ec 100644 --- a/BoxOffice.xcodeproj/project.pbxproj +++ b/BoxOffice.xcodeproj/project.pbxproj @@ -12,13 +12,14 @@ 63DF20F32970E1A0005DF7D1 /* MovieListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63DF20F22970E1A0005DF7D1 /* MovieListViewController.swift */; }; 63DF20F82970E1A1005DF7D1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 63DF20F72970E1A1005DF7D1 /* Assets.xcassets */; }; 8494905D2BA9837B00628DBB /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8494905C2BA9837B00628DBB /* String+.swift */; }; + 8494905F2BA9A8B600628DBB /* Date+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8494905E2BA9A8B600628DBB /* Date+.swift */; }; 84B8A6F52B9AFC0800F33659 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B8A6F42B9AFC0800F33659 /* HTTPMethod.swift */; }; 84B8A6F72B9B26E200F33659 /* HTTPError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B8A6F62B9B26E200F33659 /* HTTPError.swift */; }; 84CCF7E82B8F6BE400CA2EDF /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7E72B8F6BE400CA2EDF /* NetworkManager.swift */; }; 84CCF7EA2B8F6BF800CA2EDF /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7E92B8F6BF800CA2EDF /* JSONParser.swift */; }; 84CCF7EC2B8F6C0000CA2EDF /* APIURLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7EB2B8F6C0000CA2EDF /* APIURLBuilder.swift */; }; 84CCF7EE2B8F6C0900CA2EDF /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7ED2B8F6C0900CA2EDF /* NetworkError.swift */; }; - 84CCF7F02B8F6C1300CA2EDF /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7EF2B8F6C1300CA2EDF /* Query.swift */; }; + 84CCF7F02B8F6C1300CA2EDF /* APIURLCompnents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7EF2B8F6C1300CA2EDF /* APIURLCompnents.swift */; }; 84CCF7F42B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7F32B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift */; }; 84CCF7F62B8F6C4400CA2EDF /* MovieDetailDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7F52B8F6C4400CA2EDF /* MovieDetailDTO.swift */; }; 84CCF7F92B8F6C5F00CA2EDF /* ActorDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF7F82B8F6C5F00CA2EDF /* ActorDTO.swift */; }; @@ -29,7 +30,6 @@ 84CCF8032B8F6CA000CA2EDF /* NationDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8022B8F6CA000CA2EDF /* NationDTO.swift */; }; 84CCF8052B8F6CAE00CA2EDF /* ShowTypeDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8042B8F6CAE00CA2EDF /* ShowTypeDTO.swift */; }; 84CCF8072B8F6CBD00CA2EDF /* StaffDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CCF8062B8F6CBD00CA2EDF /* StaffDTO.swift */; }; - 84DFC3792BA02FCD00E1F04D /* dateFormmater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DFC3782BA02FCD00E1F04D /* dateFormmater.swift */; }; 84DFC37D2BA29AEC00E1F04D /* MovieListCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DFC37C2BA29AEC00E1F04D /* MovieListCollectionViewCell.swift */; }; E4C414782B7DEE2100BB8860 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = E4C414772B7DEE2100BB8860 /* .swiftlint.yml */; }; /* End PBXBuildFile section */ @@ -51,6 +51,7 @@ 63DF20F72970E1A1005DF7D1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 63DF20FC2970E1A1005DF7D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8494905C2BA9837B00628DBB /* String+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+.swift"; sourceTree = ""; }; + 8494905E2BA9A8B600628DBB /* Date+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+.swift"; sourceTree = ""; }; 84B8A6DD2B99BA2200F33659 /* BoxOffice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BoxOffice.app; sourceTree = BUILT_PRODUCTS_DIR; }; 84B8A6DE2B99BA2200F33659 /* BoxOfficeUnitTest.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BoxOfficeUnitTest.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 84B8A6F42B9AFC0800F33659 /* HTTPMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPMethod.swift; sourceTree = ""; }; @@ -59,7 +60,7 @@ 84CCF7E92B8F6BF800CA2EDF /* JSONParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONParser.swift; sourceTree = ""; }; 84CCF7EB2B8F6C0000CA2EDF /* APIURLBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIURLBuilder.swift; sourceTree = ""; }; 84CCF7ED2B8F6C0900CA2EDF /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = ""; }; - 84CCF7EF2B8F6C1300CA2EDF /* Query.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Query.swift; sourceTree = ""; }; + 84CCF7EF2B8F6C1300CA2EDF /* APIURLCompnents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIURLCompnents.swift; sourceTree = ""; }; 84CCF7F32B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyBoxOfficeDTO.swift; sourceTree = ""; }; 84CCF7F52B8F6C4400CA2EDF /* MovieDetailDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieDetailDTO.swift; sourceTree = ""; }; 84CCF7F82B8F6C5F00CA2EDF /* ActorDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActorDTO.swift; sourceTree = ""; }; @@ -70,7 +71,6 @@ 84CCF8022B8F6CA000CA2EDF /* NationDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NationDTO.swift; sourceTree = ""; }; 84CCF8042B8F6CAE00CA2EDF /* ShowTypeDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowTypeDTO.swift; sourceTree = ""; }; 84CCF8062B8F6CBD00CA2EDF /* StaffDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaffDTO.swift; sourceTree = ""; }; - 84DFC3782BA02FCD00E1F04D /* dateFormmater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dateFormmater.swift; sourceTree = ""; }; 84DFC37C2BA29AEC00E1F04D /* MovieListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieListCollectionViewCell.swift; sourceTree = ""; }; E4C414772B7DEE2100BB8860 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; /* End PBXFileReference section */ @@ -109,7 +109,7 @@ 84CCF8082B8F6CE000CA2EDF /* App */, 63DF20F22970E1A0005DF7D1 /* MovieListViewController.swift */, 84DFC37C2BA29AEC00E1F04D /* MovieListCollectionViewCell.swift */, - 8494905C2BA9837B00628DBB /* String+.swift */, + 849490602BA9FFD500628DBB /* Extension */, 84CCF7F12B8F6C2700CA2EDF /* Model */, 84CCF7E62B8F6BDA00CA2EDF /* Network */, 63DF20F72970E1A1005DF7D1 /* Assets.xcassets */, @@ -118,12 +118,20 @@ path = BoxOffice; sourceTree = ""; }; + 849490602BA9FFD500628DBB /* Extension */ = { + isa = PBXGroup; + children = ( + 8494905C2BA9837B00628DBB /* String+.swift */, + 8494905E2BA9A8B600628DBB /* Date+.swift */, + ); + path = Extension; + sourceTree = ""; + }; 84B8A6F82B9B392000F33659 /* Errors */ = { isa = PBXGroup; children = ( 84B8A6F62B9B26E200F33659 /* HTTPError.swift */, 84CCF7ED2B8F6C0900CA2EDF /* NetworkError.swift */, - 84DFC3782BA02FCD00E1F04D /* dateFormmater.swift */, ); path = Errors; sourceTree = ""; @@ -132,7 +140,7 @@ isa = PBXGroup; children = ( 84CCF7EB2B8F6C0000CA2EDF /* APIURLBuilder.swift */, - 84CCF7EF2B8F6C1300CA2EDF /* Query.swift */, + 84CCF7EF2B8F6C1300CA2EDF /* APIURLCompnents.swift */, ); path = APIManager; sourceTree = ""; @@ -314,13 +322,12 @@ buildActionMask = 2147483647; files = ( 63DF20F32970E1A0005DF7D1 /* MovieListViewController.swift in Sources */, - 84CCF7F02B8F6C1300CA2EDF /* Query.swift in Sources */, + 84CCF7F02B8F6C1300CA2EDF /* APIURLCompnents.swift in Sources */, 63DF20EF2970E1A0005DF7D1 /* AppDelegate.swift in Sources */, 84CCF7F92B8F6C5F00CA2EDF /* ActorDTO.swift in Sources */, 84CCF7F62B8F6C4400CA2EDF /* MovieDetailDTO.swift in Sources */, 84CCF7EA2B8F6BF800CA2EDF /* JSONParser.swift in Sources */, 84CCF8032B8F6CA000CA2EDF /* NationDTO.swift in Sources */, - 84DFC3792BA02FCD00E1F04D /* dateFormmater.swift in Sources */, 84DFC37D2BA29AEC00E1F04D /* MovieListCollectionViewCell.swift in Sources */, 84B8A6F52B9AFC0800F33659 /* HTTPMethod.swift in Sources */, 8494905D2BA9837B00628DBB /* String+.swift in Sources */, @@ -328,6 +335,7 @@ 84CCF8012B8F6C9700CA2EDF /* GenreDTO.swift in Sources */, 84CCF7FF2B8F6C8900CA2EDF /* DirectorDTO.swift in Sources */, 84CCF7F42B8F6C3800CA2EDF /* DailyBoxOfficeDTO.swift in Sources */, + 8494905F2BA9A8B600628DBB /* Date+.swift in Sources */, 84CCF7FB2B8F6C6900CA2EDF /* AuditDTO.swift in Sources */, 84CCF7EE2B8F6C0900CA2EDF /* NetworkError.swift in Sources */, 84CCF8072B8F6CBD00CA2EDF /* StaffDTO.swift in Sources */, diff --git a/BoxOffice/MovieListCollectionViewCell.swift b/BoxOffice/MovieListCollectionViewCell.swift index 9b50089d..05779f23 100644 --- a/BoxOffice/MovieListCollectionViewCell.swift +++ b/BoxOffice/MovieListCollectionViewCell.swift @@ -30,7 +30,7 @@ class MovieListCollectionViewCell: UICollectionViewCell { private let movieTitleLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false - label.font = UIFont.systemFont(ofSize: 25, weight: .semibold) + label.font = UIFont.systemFont(ofSize: 21, weight: .semibold) return label }() @@ -72,11 +72,10 @@ class MovieListCollectionViewCell: UICollectionViewCell { override init(frame: CGRect) { super.init(frame: frame) - configureBorder() setupUI() - } + required init?(coder: NSCoder) { super.init(coder: coder) } @@ -88,6 +87,7 @@ extension MovieListCollectionViewCell { layer.borderWidth = 0.2 layer.borderColor = UIColor.lightGray.cgColor } + private func setupUI() { contentView.addSubview(rankStackView) contentView.addSubview(movieTitleStackView) @@ -113,7 +113,7 @@ extension MovieListCollectionViewCell { private func setupMovieTitleStackViewConstraint() { NSLayoutConstraint.activate([ - movieTitleStackView.leadingAnchor.constraint(equalTo: rankStackView.trailingAnchor, constant: 30), + movieTitleStackView.leadingAnchor.constraint(equalTo: rankStackView.trailingAnchor, constant: 25), movieTitleStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16) ]) } @@ -130,7 +130,7 @@ extension MovieListCollectionViewCell { rankLabel.text = movieInfo.rank rankChangeLabel.text = movieInfo.rankChanges movieTitleLabel.text = movieInfo.movieName - audienceLabel.text = "오늘 :\(movieInfo.audienceCount.formatNumberString())명 / 총 :\( movieInfo.audienceAccumulated.formatNumberString())명" + audienceLabel.text = "오늘 : \(movieInfo.audienceCount.formatNumberString())명 / 총 : \( movieInfo.audienceAccumulated.formatNumberString())명" if movieInfo.rankOldAndNew == "NEW" { rankChangeLabel.text = "신작" @@ -150,5 +150,4 @@ extension MovieListCollectionViewCell { } } } - } diff --git a/BoxOffice/MovieListViewController.swift b/BoxOffice/MovieListViewController.swift index 4b7e03ce..45ea18f6 100644 --- a/BoxOffice/MovieListViewController.swift +++ b/BoxOffice/MovieListViewController.swift @@ -4,14 +4,14 @@ // // Created by kjs on 13/01/23. // -import SwiftUI +import OSLog import UIKit final class MovieListViewController: UIViewController { private let networkManager = NetworkManager.shared - private var boxOfficeDataArray:[DailyBoxOfficeDTO.BoxOfficeDTO.MovieInfo] = [] - let apiBuilder = APIURLBuilder() + private var dailyBoxOfficeList:[DailyBoxOfficeDTO.BoxOfficeDTO.MovieInfo] = [] + private let apiBuilder = APIURLBuilder() private let collectionView: UICollectionView = { let layout = UICollectionViewFlowLayout() @@ -31,49 +31,43 @@ final class MovieListViewController: UIViewController { private lazy var refreshControl: UIRefreshControl = { let refreshControl = UIRefreshControl() - refreshControl.addTarget(self, action: #selector(reload), for: .valueChanged) + refreshControl.addTarget(self, action: #selector(loadData), for: .valueChanged) return refreshControl - }() override func viewDidLoad() { super.viewDidLoad() - title = Date().yesterday + title = Date().yesterday(format: Date.yyyyMMddHyphen) collectionView.dataSource = self collectionView.delegate = self - collectionView.refreshControl = refreshControl setupCollectionView() view.addSubview(activityIndicator) - + loadData() + } + + @objc + private func loadData() { Task { - let data = try await networkManager.performRequest(with: apiBuilder.buildDailyBoxOfficeAPI(targetDate: APIURLCompnents.QueryValues.targetDate ?? "")) - - guard let DTO = JSONParser().decode(data, DTO: DailyBoxOfficeDTO.self), - let boxOfficeList = DTO.boxOfficeResult.dailyBoxOfficeList + let data = try await networkManager.performRequest(with: apiBuilder.buildDailyBoxOfficeAPI(targetDate: APIURLCompnents.QueryValues.targetDate)) + + guard let parsedData = JSONParser().decode(data, DTO: DailyBoxOfficeDTO.self), + let dailyBoxOfficeData = parsedData.boxOfficeResult.dailyBoxOfficeList else { return } - - boxOfficeDataArray = boxOfficeList + dailyBoxOfficeList = dailyBoxOfficeData collectionView.reloadData() - activityIndicator.isHidden = true + activityIndicator.removeFromSuperview() + refreshControl.endRefreshing() } } - - @objc - func reload() { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { - self.collectionView.reloadData() - self.refreshControl.endRefreshing() - } - } - + private func setupCollectionView() { collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell") collectionView.register(MovieListCollectionViewCell.self, forCellWithReuseIdentifier: "MovieListCollectionViewCell") - + collectionView.refreshControl = refreshControl view.addSubview(collectionView) collectionView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ @@ -90,13 +84,13 @@ extension MovieListViewController: UICollectionViewDataSource, UICollectionViewD guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MovieListCollectionViewCell", for: indexPath) as? MovieListCollectionViewCell else { fatalError("fatalError") } - cell.configureCell(with: boxOfficeDataArray[indexPath.row]) + cell.configureCell(with: dailyBoxOfficeList[indexPath.row]) cell.addSubview(MovieListCollectionViewCell()) return cell } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - boxOfficeDataArray.count + dailyBoxOfficeList.count } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { @@ -109,26 +103,3 @@ extension MovieListViewController: UICollectionViewDataSource, UICollectionViewD 0 } } - - - -//import SwiftUI -//struct ViewControllerRepresentable: UIViewControllerRepresentable { -// -// // update -// func updateUIViewController(_ uiViewController: UIViewController, context: Context){ -// -// } -// // makeui -// @available(iOS 13.0, *) -// func makeUIViewController(context: Context) -> UIViewController { -// MovieListViewController() -// } -//} -// -//struct ViewController_Previews: PreviewProvider { -// static var previews: some View{ -// ViewControllerRepresentable().previewDisplayName("아이폰 15프로") -// } -//} - diff --git a/BoxOffice/Network/APIManager/APIURLBuilder.swift b/BoxOffice/Network/APIManager/APIURLBuilder.swift index 26efac38..618f2a0c 100644 --- a/BoxOffice/Network/APIManager/APIURLBuilder.swift +++ b/BoxOffice/Network/APIManager/APIURLBuilder.swift @@ -32,14 +32,14 @@ struct APIURLBuilder { } extension APIURLBuilder { - func buildDailyBoxOfficeAPI(targetDate: APIURLCompnents.QueryValues, keys: APIURLCompnents.QueryKeys..., values: Any...) -> URL? { + func buildDailyBoxOfficeAPI(targetDate: String, keys: APIURLCompnents.QueryKeys..., values: Any...) -> URL? { let dict: [APIURLCompnents.QueryKeys: Any] = zip(keys, values).reduce(into: [:]) { partialResult, now in partialResult[now.0] = now.1 } return buildUrl(apiType: .dailyBoxOffice, requiredQuery: targetDate, queries: dict).url } - private func buildUrl(apiType: APIType, requiredQuery: APIURLCompnents.QueryValues, queries: [APIURLCompnents.QueryKeys: Any]) -> URLComponents { + private func buildUrl(apiType: APIType, requiredQuery: String, queries: [APIURLCompnents.QueryKeys: Any]) -> URLComponents { var components = URLComponents() components.scheme = APIURLCompnents.schema components.host = APIURLCompnents.host @@ -47,7 +47,7 @@ extension APIURLBuilder { components.queryItems = [ URLQueryItem(name: "key", value: APIURLCompnents.QueryValues.APIKey.rawValue), - URLQueryItem(name: apiType.rawValue , value: requiredQuery.rawValue) + URLQueryItem(name: apiType.rawValue , value: requiredQuery) ] queries.forEach { (key: APIURLCompnents.QueryKeys, value: Any) in components.queryItems?.append(URLQueryItem(name: key.rawValue, diff --git a/BoxOffice/Network/APIManager/APIURLCompnents.swift b/BoxOffice/Network/APIManager/APIURLCompnents.swift index f12ef770..94cef516 100644 --- a/BoxOffice/Network/APIManager/APIURLCompnents.swift +++ b/BoxOffice/Network/APIManager/APIURLCompnents.swift @@ -26,7 +26,7 @@ struct APIURLCompnents { enum QueryValues: String { case APIKey = "23a93cbbbc8fdc2ae474716728465cca" - static var targetDate = Date().yesterday + static var targetDate = Date().yesterday(format: "yyyyMMdd") case movieCode = "20124079" } } diff --git a/BoxOffice/Network/Errors/NetworkError.swift b/BoxOffice/Network/Errors/NetworkError.swift index 6ec17cf4..3fb9a642 100644 --- a/BoxOffice/Network/Errors/NetworkError.swift +++ b/BoxOffice/Network/Errors/NetworkError.swift @@ -6,7 +6,7 @@ // enum NetworkError: Error { - case responseError + case invalidUrl + case invalidResponse case parseError - case dataError } diff --git a/NetworkManager.swift b/NetworkManager.swift index 1b02a3b8..bd7631b5 100644 --- a/NetworkManager.swift +++ b/NetworkManager.swift @@ -15,33 +15,36 @@ class NetworkManager { func performRequest(with url: URL?) async throws -> Data { guard let url else { - throw NetworkError.dataError + throw NetworkError.invalidUrl } + let session = URLSession(configuration: .default) let request = makeRequest(with: url, method: .get, headers: nil) let (data, response) = try await session.data(for: request) guard let statusCode = (response as? HTTPURLResponse)?.statusCode else { - throw NetworkError.responseError + throw NetworkError.invalidResponse } + guard (200 ..< 299) ~= statusCode else { - throw responseVerify(with: response as! HTTPURLResponse) + throw verifyStatusCode(with: response as! HTTPURLResponse) } + return data } func makeRequest(with url: URL, method: HTTPMethod, headers: [String: String]?) -> URLRequest { var request = URLRequest(url: url) request.httpMethod = method.rawValue - headers?.forEach { key, value in request.addValue(value, forHTTPHeaderField: key) } + return request } - private func responseVerify(with HTTPResponse: HTTPURLResponse) -> Error { + private func verifyStatusCode(with HTTPResponse: HTTPURLResponse) -> Error { switch HTTPResponse.statusCode { case (300...399): return HTTPError.redirectionMessages(HTTPResponse.statusCode, HTTPResponse.debugDescription) From 73a23ea497942eed94640560252050b6c61cbf04 Mon Sep 17 00:00:00 2001 From: yoruck2 Date: Wed, 20 Mar 2024 18:56:10 +0900 Subject: [PATCH 18/18] =?UTF-8?q?refactor:=20=20dateFormatter=EC=97=90=20T?= =?UTF-8?q?imeZone=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BoxOffice/Extension/Date+.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BoxOffice/Extension/Date+.swift b/BoxOffice/Extension/Date+.swift index b296e6e6..b7eec1d8 100644 --- a/BoxOffice/Extension/Date+.swift +++ b/BoxOffice/Extension/Date+.swift @@ -14,6 +14,8 @@ extension Date { func yesterday(format: String) -> String { let dateFormatter = DateFormatter() dateFormatter.dateFormat = format + dateFormatter.timeZone = TimeZone(abbreviation: "UTC") + let today = Date() let timezone = TimeZone.autoupdatingCurrent let secondsFromGMT = timezone.secondsFromGMT(for: today)