Viewstateextensions

RxSwift Reactive extensions for eliminating the same boilerplate code.

Observable Type

extension ObservableType where Element: ViewStateProtocol {

    var success: Observable<Element.FulfilledType> {
        return self.map { $0.success }.unwrap()
    }

    var error: Observable<Element.ErrorType> {
        return self.map { $0.error }.unwrap()
    }

    var loading: Observable<Element.LoadingType> {
        return self.map { $0.loading }.unwrap()
    }

    var empty: Observable<Element.EmptyType> {
        return self.map { $0.empty }.unwrap()
    }
}

Driver Type

public extension Driver {
    func unwrap<T>() -> Driver<T> where Element == T? {
        return self.flatMap { Driver.from(optional: $0) }
    }
}

public extension Driver where Element: ViewStateProtocol {
    var success: Driver<Element.SuccessType> {
        return self.map { $0.success }.unwrap()
    }
    
    var error: Driver<Element.ErrorType> {
        return self.map { $0.error }.unwrap()
    }
    
    var loading: Driver<Element.LoadingType> {
        return self.map { $0.loading }.unwrap()
    }

    var empty: Driver<Element.EmptyType> {
        return self.map { $0.empty }.unwrap()
    }
}

Usage

Observable Type

let viewState = customViewModel
	.output
	.viewState
	.asObservable()

viewState
	.success
	.map(\.items)
	.bind(to: customViewModel.appListItemsObserver)
	.disposed(by: disposeBag)

Driver Type

fulfilled
	.map(\.tokenExpire)
	.subscribe(onNext: { [weak customView] isVisible in
		customView?.setButtonVisibility(visible: isVisible)
	})
	.disposed(by: disposeBag)

error
	.mapToTrue()
	.bind(to: customView.isInputVisible)
	.disposed(by: disposeBag)

We get \.tokenExpire from ViewStateCustomModel file in which we have custom model CustomState: ViewSuccess conformance which in relation the extension of Driver where Element: ViewStateProtocol allows us to unwrap internally.

Syntactic Sugar

Extra helper methods for syntactic sugar around these things.

public extension ViewState {
    var isLoading: Bool {
        return self.loading != nil
    }
    var isNotLoading: Bool {
        return !isLoading
    }
    var isNotEmpty: Bool {
        return self.empty == nil
    }
    var isError: Bool {
        return self.error != nil
    }
}