-1

Where is the correct place I should put the code that would trigger a loading to display in my app.

It is correct to do is on view? since it is displaying something on screen, so it fits as a UI logic

class ViewController: UIViewController {
 func fetchData() {
     showLoading()
     interactor?.fetchData()
 }
}

or on interactor? since it's a business logic. something like, everytime a request is made, we should display a loading. View only knows how to construct a loading, not when to display it.

class Interactor {
   func fetchData() {
     presenter?.presentLoading(true)
     worker?.fetchData() { (data) [weak self] in
          presenter?.presentLoading(false)
          self?.presenter?.presentData(data)
     }
   }
}

same question applies to MVVM and MVP.

  • Since the Interactor is independent of any view logic, and the presenter is responsible for preparing/handling the UI, it is better to control the loading view via the presenter. So, you should create functions for displaying and hiding the loading view in the view, and call it from the presenter whenever required. It goes the same with MVP or MVVM too. – brainforked Nov 16 '19 at 19:23
  • But presenter only gets called when my data had finished being fetched. And displaying a loading is not even needed anymore – Danilo Henrique Nov 17 '19 at 00:08
  • How do you trigger the data fetch in Interactor? Does it get called by the presenter, or some other event? – brainforked Nov 17 '19 at 05:37
  • data is fetched on worker – Danilo Henrique Nov 18 '19 at 00:43

2 Answers2

0

it is totally up to you . i am showing loading using an Observable . in my viewModel there is an enum called action :

enum action {
    case success(count:Int)
    case deleteSuccess
    case loading
    case error
}

and an Observable of action type :

var actionsObservable = PublishSubject<action>()

then , before fetching data i call onNext method of actionObservable(loading)

and subscribing to it in viewController :

vm.actionsObserver
    .observeOn(MainScheduler.instance)
    .subscribe(onNext: { (action) in
        switch action {
        case .success(let count):
     if(count == 0){
                self.noItemLabel.isHidden = false
            }
            else{
            self.noItemLabel.isHidden = true
            }
            self.refreshControl.endRefreshing()
            self.removeSpinner()
        case .loading:
            self.showSpinner(onView : self.view)
        case .error:
            self.removeSpinner()

        }
    }, onError: { (e) in
        print(e)
    }).disposed(by: disposeBag)
Arvin Rezaei
  • 818
  • 10
  • 25
0

You can use the delegate or completion handler to the update the UI from view model.

class PaymentViewController: UIViewController {
// for UI update
func showLoading() {
        self.showLoader()
   }
    
    func stopLoading() {
        self.removeLoader()
    }
}

protocol PaymentOptionsDelegate : AnyObject {
    func showLoading()
    func stopLoading()
}

class PaymentOptionsViewModel {
   weak var delegate : PaymentOptionsDelegate?

func fetchData() {
    delegate?.showLoading()
    delegate?.stopLoading()
}

}
Diva
  • 129
  • 8