-
Notifications
You must be signed in to change notification settings - Fork 24
박스오피스 앱 [STEP4] Jane, Tommy #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: d_Tommy
Are you sure you want to change the base?
Changes from 34 commits
9ac6ae6
9d9a6af
81e2537
3dd3e49
94ab493
d35aae1
8863c93
c1e9745
aa4f585
a921b87
03078cc
f843f8d
8f191c6
7145e1f
785a5a1
9f48613
e174da9
a4df8ab
60feb91
f07e7fe
a3dec89
6177f97
4e4a95a
bfea546
93cc3ef
66abaed
48e2ab3
59e955d
7af04a8
e1a0597
db3b894
51585f2
290348f
b49421f
7a6b0c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| // | ||
| // MoviePosterAPI.swift | ||
| // BoxOffice | ||
| // | ||
| // Created by nayeon on 3/19/24. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| enum MoviePosterAPI { | ||
| case requestMoviePosterImage(userkey: String, query: String) | ||
| } | ||
|
|
||
| extension MoviePosterAPI: TargetType { | ||
|
|
||
| var baseURL: String { | ||
| return "https://dapi.kakao.com/v2" | ||
| } | ||
|
|
||
| var method: HTTPMethod { | ||
| return .get | ||
| } | ||
|
|
||
| var path: String { | ||
| switch self { | ||
| case .requestMoviePosterImage: | ||
| return "/search/image" | ||
| } | ||
| } | ||
|
|
||
| var parameters: RequestParameters { | ||
| switch self { | ||
| case let .requestMoviePosterImage(_, movieName): | ||
| return .query(["query": "\(movieName) 영화 포스터", | ||
| "size": "1", | ||
| "sort": "accuracy"]) | ||
| } | ||
| } | ||
|
|
||
| var header: HeaderType { | ||
| switch self { | ||
| case let .requestMoviePosterImage(apiKey, _): | ||
| return .custom(["Authorization": "KakaoAK \(apiKey)"]) | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| // | ||
| // MoviePosterDTO.swift | ||
| // BoxOffice | ||
| // | ||
| // Created by nayeon on 3/19/24. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| struct MoviePosterDTO: Codable { | ||
| let meta: Meta | ||
| let documents: [Document] | ||
| } | ||
|
|
||
| struct Meta: Codable { | ||
| let totalCount: Int | ||
| let pageableCount: Int | ||
| let isEnd: Bool | ||
|
|
||
| enum CodingKeys: String, CodingKey { | ||
| case totalCount = "total_count" | ||
| case pageableCount = "pageable_count" | ||
| case isEnd = "is_end" | ||
| } | ||
| } | ||
|
|
||
| struct Document: Codable { | ||
| let collection: String | ||
| let thumbnailURL: String | ||
| let imageURL: String | ||
| let width: Int | ||
| let height: Int | ||
| let displaySiteName: String | ||
| let docURL: String | ||
| let datetime: String | ||
|
|
||
| enum CodingKeys: String, CodingKey { | ||
| case collection | ||
| case thumbnailURL = "thumbnail_url" | ||
| case imageURL = "image_url" | ||
| case width | ||
| case height | ||
| case displaySiteName = "display_sitename" | ||
| case docURL = "doc_url" | ||
| case datetime | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| // | ||
| // MoviePosterAPIService.swift | ||
| // BoxOffice | ||
| // | ||
| // Created by nayeon on 3/19/24. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| final class MoviePosterAPIService: BaseAPIService { | ||
|
|
||
| override init(provider: Requestable) { | ||
| super.init(provider: NetworkProvider()) | ||
| } | ||
|
|
||
| func requestMoviePosterAPI(userKey: String, query: String, completion: @escaping ((NetworkResult<Any>) -> Void)) { | ||
| guard let request = try? MoviePosterAPI | ||
| .requestMoviePosterImage(userkey: userKey, query: query) | ||
| .creatURLRequest() | ||
| else { | ||
| completion(.networkFail) | ||
| return | ||
| } | ||
|
|
||
| provider.request(request) { result in | ||
| switch result { | ||
| case .success(let result): | ||
| let networkResult = self.judgeStatus(by: result.response.statusCode, | ||
| result.data, | ||
| MoviePosterDTO.self) | ||
| completion(networkResult) | ||
| case .failure(_): | ||
| completion(.networkFail) | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| // | ||
| // DefaultMoviePosterRepository.swift | ||
| // BoxOffice | ||
| // | ||
| // Created by nayeon on 3/19/24. | ||
| // | ||
|
|
||
| import UIKit | ||
|
|
||
| final class DefaultMoviePosterRepository: MoviePosterRepository { | ||
|
|
||
| private let apiService: MoviePosterAPIService | ||
|
|
||
| init(apiService: MoviePosterAPIService) { | ||
| self.apiService = apiService | ||
| } | ||
|
|
||
| func fetchMoviePoster(query: String, completion: @escaping (NetworkResult<MoviePosterEntity>) -> Void) { | ||
| guard let apiKey = Bundle.main.object(forInfoDictionaryKey: "KAKAO_KEY") as? String else { return } | ||
|
|
||
| apiService.requestMoviePosterAPI(userKey: apiKey, query: query) { result in | ||
| switch result { | ||
| case .success(let data): | ||
| if let dto = data as? MoviePosterDTO, | ||
| let firstImageUrl = dto.documents.first?.imageURL { | ||
| self.loadImage(from: firstImageUrl) { result in | ||
| switch result { | ||
| case .success(let image): | ||
| let posterEntity = MoviePosterEntity(image: image) | ||
| DispatchQueue.main.async { | ||
| completion(.success(posterEntity)) | ||
| } | ||
| case .failure: | ||
| completion(.networkFail) | ||
| } | ||
| } | ||
| } else { | ||
| completion(.pathError) | ||
| } | ||
| case .pathError: | ||
| completion(.pathError) | ||
| case .requestError: | ||
| completion(.requestError) | ||
| case .serverError: | ||
| completion(.serverError) | ||
| case .networkFail: | ||
| completion(.networkFail) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private func loadImage(from imageUrl: String, completion: @escaping (Result<UIImage, Error>) -> Void) { | ||
| guard let url = URL(string: imageUrl) else { | ||
| completion(.failure(NetworkError.invalidURL)) | ||
| return | ||
| } | ||
|
|
||
| URLSession.shared.dataTask(with: url) { data, response, error in | ||
| if let error = error { | ||
| completion(.failure(error)) | ||
| return | ||
| } | ||
|
|
||
| guard let data = data, let image = UIImage(data: data) else { | ||
| completion(.failure(NetworkError.invalidURL)) | ||
| return | ||
| } | ||
| completion(.success(image)) | ||
| }.resume() | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| // | ||
| // DefaultMovieRepository.swift | ||
| // BoxOffice | ||
| // | ||
| // Created by nayeon on 3/13/24. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| final class DefaultMovieRepository: MovieRepository { | ||
|
|
||
| private let apiService: MovieAPIService | ||
|
|
||
| init(apiService: MovieAPIService) { | ||
| self.apiService = apiService | ||
| } | ||
|
|
||
| func fetchMovieDetail(movieCode: String, completion: @escaping (NetworkResult<MovieEntity>) -> Void) { | ||
| guard let apiKey = Bundle.main.object(forInfoDictionaryKey: "API_KEY") as? String else { return } | ||
|
|
||
| apiService.requestMovieDetailAPI(userKey: apiKey, movieCode: movieCode) { result in | ||
| switch result { | ||
| case .success(let data): | ||
| if let dto = data as? MovieDTO { | ||
| DispatchQueue.main.async { | ||
| let movieEntity = dto.movieInformationResult.detailMovieInformation.toEntity() | ||
| completion(.success(movieEntity)) | ||
| } | ||
| } | ||
| case .pathError: | ||
| completion(.pathError) | ||
| case .requestError: | ||
| completion(.requestError) | ||
| case .serverError: | ||
| completion(.serverError) | ||
| case .networkFail: | ||
| completion(.networkFail) | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| // | ||
| // MovieEntity.swift | ||
| // BoxOffice | ||
| // | ||
| // Created by EUNJU on 3/13/24. | ||
| // | ||
|
|
||
| struct MovieEntity { | ||
| let movieName: String | ||
| let director: String | ||
| let productYear: String | ||
| let openDate: String | ||
| let showTime: String | ||
| let watchGrade: String | ||
| let nation: String | ||
| let genres: String | ||
| let actors: String | ||
|
|
||
| func getInfoArray() -> [(title: String, info: String)] { | ||
| return [ | ||
| ("감독:", director), | ||
| ("제작년도:", productYear), | ||
| ("개봉일:", openDate), | ||
| ("상영시간:", showTime), | ||
| ("관람등급:", watchGrade), | ||
| ("제작국가:", nation), | ||
| ("장르:", genres), | ||
| ("배우:", actors) | ||
| ] | ||
| } | ||
|
Comment on lines
+19
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분을 튜플로 처리하신 이유가 있을까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dictionary를 사용할 경우 순서를 지킬수 없기 때문에 순서를 지키기위해 튜플을 채택하였습니다. |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| // | ||
| // MoviePosterEntity.swift | ||
| // BoxOffice | ||
| // | ||
| // Created by nayeon on 3/19/24. | ||
| // | ||
|
|
||
| import UIKit | ||
|
|
||
| struct MoviePosterEntity { | ||
| let image: UIImage | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // | ||
| // MoviePosterRepository.swift | ||
| // BoxOffice | ||
| // | ||
| // Created by nayeon on 3/19/24. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| protocol MoviePosterRepository { | ||
| func fetchMoviePoster(query: String, completion: @escaping | ||
| (NetworkResult<MoviePosterEntity>) -> Void) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 부분은 imagery 이 없을 때, dto 가 MoviePosterDTO 타입이 아닐때,
에러가 발생하는 부분 같은데, pathError 라는 이름은 맞지 않는 것 같아요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
확인 감사합니다!
NetworkResult에.parsingError케이스 추가 후 해당 부분 수정해주었습니다!반영 커밋: 7a6b0c6