-
ReactorKit 에서 API 활용하기Swift/RxSwift 2022. 10. 15. 10:13
// 출처: https://nsios.tistory.com/141
(출처 코드를 일부 수정했습니다. )
중요한 Code
1. Controller
class APIPracticeController: UIViewController, View { var disposeBag = DisposeBag() func bind(reactor: MainReactor) { loadButton.rx.tap .map({ Reactor.Action.touchButton(index: 0) }) .bind(to: reactor.action) .disposed(by: disposeBag) reactor.state .map({$0.image}) .subscribe(onNext: {[weak self] img in guard let img = img, let self = self else { return } DispatchQueue.main.async { self.centerImageView.image = img } }) .disposed(by: disposeBag) } }
2. Reactor, Network
class MainReactor: Reactor { let network = Network() private let URLs = ["https://avatars.githubusercontent.com/u/62657991?v=4"] enum Action { case touchButton(index: Int) } enum Mutation { case setImage(image: UIImage?) } struct State { var image: UIImage? } let initialState: State init() { self.initialState = State() } func mutate(action: Action) -> Observable<Mutation> { switch action { case .touchButton(let index): return Observable.just(URLs[index]) .flatMap({ self.network.load(url: $0) }) .map({ Mutation.setImage(image: $0) }) } } func reduce(state: State, mutation: Mutation) -> State { var state = state switch mutation { case .setImage(let image): state.image = image } return state } } class Network { func load(url: String) -> Single<UIImage?> { let request = URLRequest(url: URL(string: url)!) return URLSession.shared.rx.response(request: request) .map({ UIImage(data: $0.data) }) .asSingle() } }
API Call 이용할 때 작동 순서!
1. 버튼을 누른다 -> Reactor 의 Action 에 전달.
2. func mutate(action: Action) 을 통해 return Mutation.setImage
case .touchButton(let index): return Observable.just(URLs[index]) .flatMap({ self.network.load(url: $0) }) .map({ Mutation.setImage(image: $0) }) }
3. 2 과정에서, networkCall 을 통해 URL -> Image 로 변환.
이때, flatMap 안에서 url -> Observable<UIImage> 로 변환해준다.
switch mutation { case .setImage(let image): state.image = image }
4. 그 후에는 func mutate 에서 위와 같이 state 의 image property 를 설정, 이어 ViewController 에 전달.
전체 코드
import Foundation import RxSwift import ReactorKit import UIKit import RxCocoa class APIPracticeController: UIViewController, View { var disposeBag = DisposeBag() let loadButton: UIButton = { let button = UIButton() button.setTitle("load Image", for: .normal) button.setTitleColor(.systemBlue, for: .normal) return button }() init(reactor: MainReactor) { super.init(nibName: nil, bundle: nil) self.reactor = reactor } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } lazy var centerImageView: UIImageView = { let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 350, height: 350)) imageView.image = UIImage() imageView.center = view.center imageView.backgroundColor = .magenta return imageView }() override func viewDidLoad() { super.viewDidLoad() makeUI() } func makeUI() { view.addSubview(centerImageView) view.addSubview(loadButton) loadButton.translatesAutoresizingMaskIntoConstraints = false loadButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true loadButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true } func bind(reactor: MainReactor) { loadButton.rx.tap .map({ Reactor.Action.touchButton(index: 0) }) .bind(to: reactor.action) .disposed(by: disposeBag) // reactor.state // .map({$0.image}) // .bind(to: centerImageView.rx.image) //// .bind(to: centerImageView.imag) // .disposed(by: disposeBag) reactor.state .map({$0.image}) .subscribe(onNext: {[weak self] img in if let img = img { DispatchQueue.main.async { self?.centerImageView.image = img } } else { print("img is nil") } }) .disposed(by: disposeBag) } }
import Foundation import RxSwift import ReactorKit class MainReactor: Reactor { let network = Network() private let URLs = ["https://avatars.githubusercontent.com/u/62657991?v=4"] enum Action { case touchButton(index: Int) } enum Mutation { case setImage(image: UIImage?) } struct State { var image: UIImage? } let initialState: State init() { self.initialState = State() } func mutate(action: Action) -> Observable<Mutation> { switch action { case .touchButton(let index): return Observable.just(URLs[index]) .flatMap({ self.network.load(url: $0) }) .map { img -> UIImage? in return img } .map({ Mutation.setImage(image: $0) }) } } func reduce(state: State, mutation: Mutation) -> State { var state = state switch mutation { case .setImage(let image): state.image = image } return state } } class Network { func load(url: String) -> Single<UIImage?> { let request = URLRequest(url: URL(string: url)!) print("request: \(request)") return URLSession.shared.rx.response(request: request) .map({ UIImage(data: $0.data) }) .asSingle() } }
'Swift > RxSwift' 카테고리의 다른 글
ReactorKit 으로 로그인 페이지 만들기 (0) 2022.10.14 RxAlamofire (0) 2022.10.03 RxSwift Observable, Subjects and Relays (0) 2022.10.01 UITableView (with RxSwift) (2) 2022.09.30 Login Validation (simple..) RxSwift 구현 (0) 2022.09.29