// DetailViewModel
final class DetailViewModel {
private let disposeBag = DisposeBag()
let pokemonDetailSubject = BehaviorSubject<PokemonDetail?>(value: nil)
let pokemonImageRelay = PublishRelay<UIImage?>()
func fetchPokemonDetail(for urlString: String) {
guard let url = APIEndpoint.pokemonDetailURL(for: urlString) else {
pokemonDetailSubject.onError(NetworkError.invalidUrl)
return
}
NetworkManager.shared.fetch(url: url)
.subscribe(onSuccess: { [weak self] (pokemonDetail: PokemonDetail) in
self?.pokemonDetailSubject.onNext(pokemonDetail)
self?.fetchPokemonImage(for: pokemonDetail.id)
}, onFailure: { [weak self] error in
self?.pokemonDetailSubject.onError(error)
})
.disposed(by: disposeBag)
}
func fetchPokemonImage(for id: Int) {
NetworkManager.shared.fetchPokemonImage(for: id)
.subscribe(onSuccess: { [weak self] image in
self?.pokemonImageRelay.accept(image)
}, onFailure: { [weak self] error in
self?.pokemonImageRelay.accept(nil)
})
.disposed(by: disposeBag)
}
}
NetworkManger와 ViewModel사이에 UseCase을 계층 추가
// PokemonUseCase
final class PokemonUseCase {
private let networkManager: NetworkManager
private let disposeBag = DisposeBag()
init(networkManager: NetworkManager = .shared) {
self.networkManager = networkManager
}
func fetchPokemonList(limit: Int, offset: Int) -> Single<PokemonResponse> {
guard let url = APIEndpoint.pokemonListURL(limit: limit, offset: offset) else {
return .error(NetworkError.invalidUrl)
}
return networkManager.fetch(url: url)
}
func fetchPokemonDetail(for id: Int) -> Single<PokemonDetail> {
guard let url = APIEndpoint.pokemonDetailURL(for: String(id)) else {
return .error(NetworkError.invalidUrl)
}
return networkManager.fetch(url: url)
}
func fetchPokemonImage(for id: Int) -> Single<UIImage> {
return networkManager.fetchPokemonImage(for: id)
}
}
// DetailViewModel
final class DetailViewModel {
private let disposeBag = DisposeBag()
private let useCase: PokemonUseCase
let pokemonDetailSubject = BehaviorSubject<PokemonDetail?>(value: nil)
let pokemonImageRelay = PublishRelay<UIImage?>()
init(useCase: PokemonUseCase) {
self.useCase = useCase
}
func fetchPokemonDetail(for id: Int) {
useCase.fetchPokemonDetail(for: id)
.subscribe(onSuccess: { [weak self] detail in
self?.pokemonDetailSubject.onNext(detail)
self?.fetchPokemonImage(for: id)
}, onFailure: { [weak self] error in
self?.pokemonDetailSubject.onError(error)
}).disposed(by: disposeBag)
}
func fetchPokemonImage(for id: Int) {
useCase.fetchPokemonImage(for: id)
.subscribe(onSuccess: { [weak self] image in
self?.pokemonImageRelay.accept(image)
}, onFailure: { [weak self] _ in
self?.pokemonImageRelay.accept(nil)
}).disposed(by: disposeBag)
}
}