From 33fa6ca619dfe58be0092c3830a18a5a314b6ecd Mon Sep 17 00:00:00 2001 From: Bin Date: Thu, 19 Mar 2026 19:38:09 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20MusicRespo?= =?UTF-8?q?nse,=20PodcastResponse=20=EC=A0=9C=EB=84=88=EB=A6=AD=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=ED=99=98=20=EB=B0=8F=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- challenge/challenge/Model/HomeSection.swift | 5 ++ challenge/challenge/Model/Music.swift | 25 --------- challenge/challenge/Model/Podcast.swift | 19 ------- .../challenge/Model/iTunesResponse.swift | 27 ++++++++++ .../challenge/ViewModel/HomeViewModel.swift | 2 +- .../challenge/ViewModel/SearchViewModel.swift | 51 ++++++++----------- 6 files changed, 53 insertions(+), 76 deletions(-) delete mode 100644 challenge/challenge/Model/Music.swift delete mode 100644 challenge/challenge/Model/Podcast.swift create mode 100644 challenge/challenge/Model/iTunesResponse.swift diff --git a/challenge/challenge/Model/HomeSection.swift b/challenge/challenge/Model/HomeSection.swift index af686ce..3e9beb8 100644 --- a/challenge/challenge/Model/HomeSection.swift +++ b/challenge/challenge/Model/HomeSection.swift @@ -55,3 +55,8 @@ enum LayoutType { case card case list } + +struct MusicSection { + let section: HomeSection + let items: [Music] +} diff --git a/challenge/challenge/Model/Music.swift b/challenge/challenge/Model/Music.swift deleted file mode 100644 index 21a08c4..0000000 --- a/challenge/challenge/Model/Music.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// Music.swift -// challenge -// -// Created by 손영빈 on 3/12/26. -// - -import Foundation - -struct MusicResponse: Codable { - let results: [Music] -} - -struct Music: Codable, Hashable { - let trackName: String? - let artistName: String? - let collectionName: String? - let artworkUrl60: String? // 앨범커버 - let artworkUrl100: String? -} - -struct MusicSection { - let section: HomeSection - let items: [Music] -} diff --git a/challenge/challenge/Model/Podcast.swift b/challenge/challenge/Model/Podcast.swift deleted file mode 100644 index aff4230..0000000 --- a/challenge/challenge/Model/Podcast.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// Podcast.swift -// challenge -// -// Created by 손영빈 on 3/17/26. -// - -import Foundation - -struct PodcastResponse: Codable { - let results: [Podcast] -} - -struct Podcast: Codable, Hashable { - let trackName: String? - let artistName: String? - let artworkUrl100: String? - let artworkUrl600: String? -} diff --git a/challenge/challenge/Model/iTunesResponse.swift b/challenge/challenge/Model/iTunesResponse.swift new file mode 100644 index 0000000..22dc20a --- /dev/null +++ b/challenge/challenge/Model/iTunesResponse.swift @@ -0,0 +1,27 @@ +// +// iTunesResponse.swift +// challenge +// +// Created by 손영빈 on 3/19/26. +// + +import Foundation + +struct iTunesResponse: Codable { + let results: [T] +} + +struct Music: Codable, Hashable { + let trackName: String? + let artistName: String? + let collectionName: String? + let artworkUrl60: String? // 앨범커버 + let artworkUrl100: String? +} + +struct Podcast: Codable, Hashable { + let trackName: String? + let artistName: String? + let artworkUrl100: String? + let artworkUrl600: String? +} diff --git a/challenge/challenge/ViewModel/HomeViewModel.swift b/challenge/challenge/ViewModel/HomeViewModel.swift index 8d22dd0..59ab689 100644 --- a/challenge/challenge/ViewModel/HomeViewModel.swift +++ b/challenge/challenge/ViewModel/HomeViewModel.swift @@ -42,7 +42,7 @@ class HomeViewModel: ViewModel { let observable = sectionInfo.map { section, term -> Observable in guard let url = NetworkManager.shared.url(term: term, media: "music") else { return .error(NetworkError.requestError) } return NetworkManager.shared.fetch(url: url) - .map { (response: MusicResponse) in // MusicResponse -> MusicSection으로 반환 + .map { (response: iTunesResponse) in // MusicResponse -> MusicSection으로 반환 MusicSection(section: section, items: response.results) }.asObservable() } diff --git a/challenge/challenge/ViewModel/SearchViewModel.swift b/challenge/challenge/ViewModel/SearchViewModel.swift index b7d7b78..9da5328 100644 --- a/challenge/challenge/ViewModel/SearchViewModel.swift +++ b/challenge/challenge/ViewModel/SearchViewModel.swift @@ -28,38 +28,27 @@ class SearchViewModel: ViewModel { .filter { !$0.isEmpty } .share() - let podcast = searchText - .flatMap { [weak self] term -> Observable<[Podcast]> in - guard let self else { return .just([] as [Podcast])} - guard let url = NetworkManager.shared.url(term: term, media: "podcast") else { - self.errorSubject.onNext(.requestError) - return .just([] as [Podcast]) - } - return NetworkManager.shared.fetch(url: url) - .map { (response: PodcastResponse) in response.results } - .asObservable() - .catch { [weak self] error in - self?.errorSubject.onNext(error as! NetworkError) - return .just([] as [Podcast]) - } - } - - let music = searchText - .flatMap { [weak self] term -> Observable<[Music]> in - guard let self else { return .just([] as [Music]) } - guard let url = NetworkManager.shared.url(term: term, media: "music") else { - self.errorSubject.onNext(.requestError) - return .just([] as [Music])} - return NetworkManager.shared.fetch(url: url) - .map { (response: MusicResponse) in response.results } - .asObservable() - .catch { [weak self] error in - self?.errorSubject.onNext(error as! NetworkError) - return .just([] as [Music]) - } - } - let searchResult = Observable.zip(podcast, music) + let podcast: Observable<[Podcast]> = search(searchText: searchText, media: "podcast") + let music: Observable<[Music]> = search(searchText: searchText, media: "music") + let searchResult = Observable.zip(podcast, music).share() return Output(searchResult: searchResult, error: errorSubject.asObservable()) } + + private func search(searchText: Observable, media: String) -> Observable<[T]> { + searchText.flatMap { [weak self] term -> Observable<[T]> in + guard let self else { return .just([])} + guard let url = NetworkManager.shared.url(term: term, media: "podcast") else { + self.errorSubject.onNext(.requestError) + return .just([]) + } + return NetworkManager.shared.fetch(url: url) + .map { (response: iTunesResponse) in response.results } + .asObservable() + .catch { [weak self] error in + self?.errorSubject.onNext(error as! NetworkError) + return .just([]) + } + } + } } From 460971ad01e76bf5dec7abb3e9e2b96f567dc24a Mon Sep 17 00:00:00 2001 From: Bin Date: Thu, 19 Mar 2026 19:47:02 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=82=B4=20=ED=95=98=EB=93=9C=EC=BD=94?= =?UTF-8?q?=EB=94=A9=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- challenge/challenge/ViewModel/SearchViewModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenge/challenge/ViewModel/SearchViewModel.swift b/challenge/challenge/ViewModel/SearchViewModel.swift index 9da5328..29750f0 100644 --- a/challenge/challenge/ViewModel/SearchViewModel.swift +++ b/challenge/challenge/ViewModel/SearchViewModel.swift @@ -38,7 +38,7 @@ class SearchViewModel: ViewModel { private func search(searchText: Observable, media: String) -> Observable<[T]> { searchText.flatMap { [weak self] term -> Observable<[T]> in guard let self else { return .just([])} - guard let url = NetworkManager.shared.url(term: term, media: "podcast") else { + guard let url = NetworkManager.shared.url(term: term, media: media) else { self.errorSubject.onNext(.requestError) return .just([]) }