Как показать / скрыть прогресс HUD, с MVVM и RxSwift в быстром

Я начинаю с MVVM, чтобы хорошо отделить логический код от представления. Но у меня есть некоторые опасения по поводу того, куда поместить код, связанный с progressHUD, при нажатии кнопки, которая делает запрос.

Раньше я делал это:

//Before 
@IBAction func startRequestTapped() {
   SVProgressHUD.show()
    self.apiClient.requestObservable().subscribe(onError: { (error) in
        SVProgressHUD.hide()                    
    }, onCompleted: { 
        SVProgressHUD.hide()                                        
    })
}

Но когда я использую mvvm, я делаю так:

//In the viewModel
public var validateButtonDidTap = PublishSubject<Void>()
init() {
    validateButtonDidTap.flatMap { (_)
        return self.apiClient.requestObservable()
    }
}


   // In the viewController
viewDidLoad() {
    let tap = self.validateButton.rx.tap
    tap.bindTo(self.viewModel.validateButtonDidTap)
}

И среди этого, я не знаю, где поставить шкатулку или шоу ProgressHUD.

3 ответа

Решение

Марк ответ правильный, но я буду вести вас шаг за шагом.

Предположим, вы попытаетесь войти.

  1. Скопируйте файл ActivityIndicator.swift в свой проект.

  2. в viewModel:

    //MARK: - Properties
    
    /// The http client
    private let apiClient: YourApiClient
    
    /// Clousure when button is tapped
    var didTappedButton: () -> Void = {}
    
    /// The user 
    var user: Observable<User>
    
    /// Is signing process in progress
    let signingIn: Observable<Bool> = ActivityIndicator().asObservable()
    
    //MARK: - Initialization
    
    init(client: YourApiClient) {
        self.client = client
    
        self.didTappedButton = { [weak self] in
            self.user = self.apiClient
                            .yourSignInRequest()
                            .trackActivity(self.signingIn)
                            .observeOn(MainScheduler.instance)
        }
    }
    
  3. Создайте расширение SVProgressHUD: (я не знаю библиотеку SVProgressHUD, но было бы что-то вроде этого. Пожалуйста, исправьте это, если необходимо)

    extension Reactive where Base: SVProgressHUD {
    
        /// Bindable sink for `show()`, `hide()` methods.
        public static var isAnimating: UIBindingObserver<Base, Bool> {
            return UIBindingObserver(UIElement: self.base) { progressHUD, isVisible in
                if isVisible {
                    progressHUD.show() // or other show methods
                } else {
                    progressHUD.dismiss() // or other hide methods
                }
            }
        }
    
    }
    
  4. В вашем viewController:

    @IBAction func startRequestTapped() {
        viewModel.didTappedButton()
    }
    
    override func viewDidLoad() {
    
        // ...
    
        viewModel.signingIn
                 .bindTo(SVProgressHUD.rx.isAnimating)
                 .addDisposableTo(disposeBag)
    }
    

Принятый ответ обновлен до Swift 4, RxSwift 4.0.0 и SVProgressHUD 2.2.2:

3- Расширение:

extension Reactive where Base: SVProgressHUD {

   public static var isAnimating: Binder<Bool> {
      return Binder(UIApplication.shared) {progressHUD, isVisible in
         if isVisible {
            SVProgressHUD.show()
         } else {
            SVProgressHUD.dismiss()
         }
      }
   }

}

4- Контроллер:

viewModel.signingIn.asObservable().bind(to: SVProgressHUD.rx.isAnimating).disposed(by: disposeBag)

Вы можете попробовать использовать ActivityIndicator,

Смотрите пример здесь: https://github.com/RxSwiftCommunity/RxSwiftUtilities

Другие вопросы по тегам