RxCleanSwift
RxCleanSwift copied to clipboard
Clean Swift 연구일지 #1
문제점
- 콜백구조 맘에 안듦
- List에 있는 Item에 대해서 (특정 IndexPath) DataStore를 통해 item을 가져와서 Show 로 보내고 다시 리스트로 되돌아갔을 때 DataPassing해줌과 동시에 interactor를 통해서 다시 present -> controller 과정을 거치는게 비효율적이라고 생각함
해결방안
1. RxSwift를 활용하여 VIP Cycle binding 및 reactive property로 설계
했을 때 장점이라면 콜백 지옥으로 부터 해방, 단점은 RxTest 잘써야되고 아직 관련 VIP템플릿이 없어서 새로만들어야함 그리고 I -> P, P -> C VIP Cycle binding처리할 때 disposable 를 반환시키는데 이에 대한 disposeBag은 Controller에서 가지고 있는게 맞다고 생각함
func configureVIPCycle() {
// configure VIP Cycle
let viewController = self
let interactor = RepositoryShowInteractor.init()
let presenter = RepositoryShowPresenter.init()
let router = RepositoryShowRouter()
// HERE!
interactor.bind(to: presenter).disposed(by: disposeBag)
presenter.bind(to: viewController).disposed(by: disposeBag)
router.bind(to: viewController).disposed(by: disposeBag)
// ....
}
2. ReactiveDataStore를 양방향으로 DataPassing해서 사용
public class ReactiveDataStore<T> {
public let store: BehaviorRelay<T>
public var value: T {
return store.value
}
init(_ data: T) {
store = .init(value: data)
}
public func update(_ data: T) {
store.accept(data)
}
public func asObservable() -> Observable<T> {
return store.asObservable()
}
}
위와 같이 어떤 Model에 대해서 Reactive하게 쓸 수 있게 Wrapping해서 만든 Class ViewModel을 다음과 같이 Store를 받아서 만들면 해당 Store가 다른 Controller에 전달되서 변경에 따라 자동으로 ViewModel의 State값도 변경됌
struct CellViewModel {
struct State {
var profileURL: URL?
var title: String?
var desc: String?
var isPinned: Bool
init(_ repo: Repository) {
self.profileURL = repo.user?.profileURL
self.title = repo.user?.username
self.desc = repo.desc
self.isPinned = repo.isPinned
}
}
let state = BehaviorRelay<State?>(value: nil)
let identifier: Int
private let disposeBag = DisposeBag()
init(_ repositoryStore: ReactiveDataStore<Repository>) {
repositoryStore
.asObservable()
.map({ State($0) })
.bind(to: state)
.disposed(by: disposeBag)
self.identifier = repositoryStore.value.id
}
}