RxSwift를 공부하면서 앱을 만들면서 MVVM패턴을 도전해보았습니다.
하지만 개발하면서 뭔가 MVVM답지 않게 프로그래밍한다고 느껴서 좀 더 찾아본 결과 Input, Output을 활용한 MVVM구조가 있어서
바로 적용해보았습니다 :)
RxSwift, Input과 Output으로 MVVM패턴 적용하기
github에서 많은 MVVM-Rx 예제들을 보면서 첫 틀을 갖추고 시작하여 많이 벗어나는 경우는 없었지만
이런 경우에는 살짝 애매했습니다.
Button Tap
-> Bind to ViewModel.buttonDidTapped
-> Business Logic in ViewModel
-> Subscribe ViewModel.result in View
-> Make event depends on result & Bind to ViewModel
맨 마지막 줄이 혼란의 핵심이었습니다.
EventBinding을 새로 Observable을 만들어서 해줘야 하나....? 고민도 되고
RxSwift 단톡방에도 여쭤봤는데 잘못 된 코드 같다고 하셔서 개선해야겠다는 생각밖에 없던 찰나
한 분이 Input, Output을 활용한 코드를 알려주셔서 더 찾아보았습니다.
기존의 제가 잘못짠 MVVM같은 경우는
간단하게 작성하겠습니다 :)
// View
class ViewController {
Observable<String>.create { observer -> Disposable in
observer.onNext("string")
return Disposables.create()
}
.bind(to: viewModel.query)
.disposed(by: self.disposeBag)
}
// ViewModel
struct ViewModel {
let query = PublishSubject<String>()
let result = query
.flatMapLatest {
return API.call($0)
}
.asDriver(onErrorJustReturn: ...)
}
지금보니 엉망이군요
기존 UI의 Event와는 연결을 잘 시켰지만 viewModel로 부터 받은 결과에 따라 다시 viewModel로 값을 전달할 때
위와 같이 만들었습니다....
개발하면서도 이건 아닌것 같은데 라는 느낌을 계속 받았죠...
그래서 위 코드를 Input, Output을 적용하여 ViewModel을 더 의미있게 분리하고 ReplaySubject를 이용하여 깔끔하게 개선했습니다.
이번에도 추상적으로 작성하겠습니다 :)
// View
class ViewController {
viewModel.inputs.query("string")
}
// ViewModel
protocol ViewModelInputs {
func query(string: String)
}
protocol ViewModelOutputs {
var result: Driver<...> { get }
}
protocol ViewModelType {
var inputs: ViewModelInputs { get }
var outputs: ViewModelOutputs { get }
}
final class ViewModel: ViewModelType, ViewModelInputs, ViewModelOutputs {
var inputs: ViewModelInputs { return self }
var outputs: ViewModelOutputs { return self }
// Input
private let _query = ReplaySubject<String>.create(bufferSize: 1)
func query(string: String) {
self._query.onNext(string)
}
let result = _query
.flatMapLatest {
return API.call($0)
}
.asDriver(onErrorJustReturn: ...)
}
이제야 깔끔해졌군요...
코드를 위와 아래, 둘 다 자세히 쓴건 아니지만 확실히 위는 아닌것 같습니다.
아래 같은 경우 Input과 Output이 확실하게 구분이 되어 ViewModel의 Data 흐름이 더 직관적으로 나타나고
제가 혼란스러웠던 부분은 ReplaySubject + func을 활용하여 깔끔하게 해결했습니다.
물론 이보다 더 낫고 효율적인 구조를 가진 코드가 있겠지만
제가 이번 MVVM-Rx를 처음으로 공부하면서 배운 것은 여기까지 입니다...!
앞으로도 다르고 새로운 것에 도전해봐야겠습니다 😀
'RxSwift' 카테고리의 다른 글
RxSwift, Network Error 처리하기 (0) | 2019.04.10 |
---|---|
RxSwift의 Subject에 대해 알아보자 (0) | 2019.03.23 |