Last active
August 6, 2019 00:50
-
-
Save GeekTree0101/7fa26211fd4552f3ab60c3ba290c8b4f to your computer and use it in GitHub Desktop.
상태기반 ViewModel 과 Repository & DataSource 활용.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import RxSwift | |
import RxCocoa | |
// MARK: - Action | |
extension Reactive where Base: TestViewModel { | |
var refresh: Binder<Void> { | |
return Binder(base) { viewModel, _ in | |
guard let id = viewModel.viewState.value?.id else { return } | |
viewModel.repository.refresh(id) | |
} | |
} | |
} | |
// MARK: - State | |
struct TestViewState { | |
var id: Int | |
var title: String | |
static let defaultState = TestViewState.init(id: -1, title: "") | |
} | |
// MARK: - ViewModel | |
class TestViewModel: ReactiveCompatible { | |
typealias ViewState = TestViewState | |
// MARK: State | |
public let viewState: ReactiveState<ViewState> = .init() | |
public lazy var error: Observable<Error> = { | |
return self.repository.error.share(replay: 1, scope: .whileConnected) | |
}() | |
private let disposeBag = DisposeBag() | |
fileprivate let repository: StoreRepository | |
init(repo: StoreRepository) { | |
self.repository = repo | |
repository.getStore() | |
.mutation(viewState, { context in | |
var (res, viewState) = context | |
viewState?.title = res?.name ?? "" | |
return viewState | |
}) | |
.disposed(by: disposeBag) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class StoreRepository { | |
var remote = StoreRemoteDataSource.init() | |
var cache = StoreCachedDataSource.init() | |
var error = PublishRelay<Error>.init() | |
private var disposeBag = DisposeBag() | |
public func refresh(_ id: Int) { | |
remote.getStore(storeID: id) | |
.subscribe(onSuccess: { [weak self] store in | |
self?.cache.setStore(store) | |
}, onError: { [weak self] error in | |
self?.error.accept(error) | |
}) | |
.dispose() | |
} | |
public func getStore() -> Observable<Store?> { | |
return cache.getStore() | |
} | |
} | |
class StoreRemoteDataSource { | |
func getStore(storeID: Int) -> Single<Store> { | |
return Single.just(Store(id: storeID, name: "apple store", productDescription: "iphone")) | |
} | |
} | |
class StoreCachedDataSource { | |
private let cachedStore = BehaviorRelay<Store?>.init(value: nil) | |
public func setStore(_ store: Store) { | |
cachedStore.accept(store) | |
} | |
public func getStore() -> Observable<Store?> { | |
return cachedStore.asObservable() | |
} | |
public func clear() { | |
cachedStore.accept(nil) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ReactiveState<Base> { | |
private let store = BehaviorRelay<Base?>.init(value: nil) | |
public let disposeBag = DisposeBag() | |
public var getter: Observable<Base?> { | |
return store.asObservable() | |
} | |
public var value: Base? { | |
get { | |
return store.value | |
} | |
set { | |
store.accept(newValue) | |
} | |
} | |
} | |
extension Observable { | |
public func mutation<Base>(_ reactiveState: ReactiveState<Base>, | |
_ mutation: @escaping (((E, Base?)) -> Base?)) -> Disposable { | |
weak var weakState = reactiveState | |
return self.withLatestFrom(reactiveState.getter) { ($0, $1) } | |
.map(mutation) | |
.subscribe(onNext: { newValue in | |
weakState?.value = newValue | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment