La fabrique mobile Viseo Toulouse

MVC Composition (Part 2)

This is a small addition to my previous MVC-Composition post. I will show how to add an ActivityIndicator while data is loading from network in a MVC-Composed architecture.

The code for the following article can be found in this repository:

https://github.com/giln/MVC-Composition-Part2.git

We want to add a small activity indicator while data is loading from the network:

Result

If you remember how Controllers are composed from my previous post:

Hierarchy

The ListViewController is only responsible for displaying cells of Apps. It is not aware of weither it is downloading data or not. So the activity indicator canno't be added in that controller.

Instead we could add the ActivityIndicator in the AppViewCoordinator, however, there is another way which is to create a new Container Controller called LoadingViewController. This controller will only be responsible for displaying the activity indicator:

//
//  LoadingViewController.swift
//  AppStoreViewer
//
//  Created by Gil Nakache on 07/01/2019.
//  Copyright © 2019 Viseo. All rights reserved.
//

import UIKit

public class LoadingViewController: UIViewController {
    // MARK: - Variables

    private let contentViewController: UIViewController
    private let activityIndicator = UIActivityIndicatorView(style: .gray)

    // MARK: - Init

    init(contentViewController: UIViewController) {
        self.contentViewController = contentViewController
        super.init(nibName: nil, bundle: nil)
    }

    public required init?(coder _: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // MARK: - Lifecycle

    public override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.white
        activityIndicator.hidesWhenStopped = true

        add(asChildViewController: contentViewController)

        view.addSubview(activityIndicator)

        activityIndicator.center(in: view)
    }

    // MARK: - Public functions

    public func startLoading() {
        contentViewController.view.isHidden = true
        activityIndicator.startAnimating()
    }

    public func endLoading() {
        activityIndicator.stopAnimating()
        contentViewController.view.isHidden = false
    }
}

The code is very simple. This controller is initialized with another controller which is added as a child View Controller.

When you call the method startLoading, you hide the content a and display the activity indicator and when you call endLoading, you hide the indicator and display the content.

Here is how we use it from the AppViewCoordinator. We start by declaring it as a variable:

private lazy var loadingViewController = LoadingViewController(contentViewController: appsViewController)

The in the viewDidLoad method we replace the add method with the following:

add(asChildViewController: loadingViewController)

Finally, we modify our viewWillAppear code by calling the startLoading and endLoading methods:

public override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        let ressource = AppStoreRessource()

        loadingViewController.startLoading()
        ressource.getApps(top: 200, appType: appType) { apps, _ in
            //
            self.loadingViewController.endLoading()
            self.apps = apps
            self.appsViewController.list = apps
        }
    }

Creating a ViewController may seem a little overkill just to add a simple Activity Indicator, however we now have a nice reusable LoadingViewController that can be used anytime you need to add an Activity Indicator to a view.

Here is the new hierarchy of controllers for this application:

NewHierarchy

All the code above can be found in the following repository:

https://github.com/giln/MVC-Composition-Part2.git

Tagged with: