Cleaning AppDelegate or SceneDelegate using ViewControllerFactory

Arifin Firdaus
Bootcampers
Published in
2 min readOct 3, 2021
Factory Design Pattern Illustration

Overview

AppDelegate or SceneDelegate is the main file that we as iOS developers know to configure, inject, or instantiate a global instance or frameworks. This place become essential, especially because it is actually the starting point of our app.

Because it knows so many things, like configuring the frameworks, handling push notifications routing, checking app’s life cycle, and others, this place can be easily messy. When you notice this class is doing many different things, we can separate the responsibility of creating the rootViewController into another component, like a factory class.

A Factory in the AppDelegate or SceneDelegate

Factory class applied in AppDelegate / SceneDelegate

A factory is one of the creational design pattern. It hides the complexity of creating object and only needs given dependency, if needed. The Factory API we need is like this :

protocol TransactionsViewControllerFactory {
func makeTransactionsViewController() -> UIViewController
}

Since we don’t need another implementation for the factory in this example, we can get rid of the protocol , and change it to a class with static method instead.

final class TransactionsViewControllerFactory {    private init() { } // we don't need the init at this example.    static func makeTransactionsViewController() -> UIViewController {

let storyboard = UIStoryboard(name: "Main", bundle: .main)
let identifier = "TransactionsViewController"
let viewController = storyboard.instantiateViewController(identifier: identifier) as! TransactionsViewController

let loader = LocalTransactionLoader(store: CoreDataTransactionStore(.persistent))
let presenter = DefaultTransactionsPresenter(loader: loader)

viewController.presenter = presenter
viewController.onAddTransactionButtonTapped = self.presentAddTranstionViewController(_:)
presenter.view = viewController

return viewController
}
}

Another example of using the factory is on the code implemention of presentAddTranstionViewController function. Its using another ViewController Factory to instantiate the component.

private static func presentAddTranstionViewController(_ transactionsVC: TransactionsViewController) -> Void {

let addTransactionVC = AddTransactionsViewControllerFactory.makeAddTransactionViewController(transactionsVC: transactionsVC)
let addTransactionNC = UINavigationController(rootViewController: addTransactionVC)
transactionsVC.present(addTransactionNC, animated: true, completion: nil)
}

To enable the ViewController creation as the SUT (System Under Tests) in the test target, we can provide a dependency into the factory method of the Factory class.

final class TransactionsViewControllerFactory {  // ...
static func makeTransactionsViewController(presenter: TransactionsPresenter) -> UIViewController {
// Injecting the given presenter
return transactionsViewController
}
}

Another options is to create the default arguments on the method, so that the AppDelegate does not need to create the ViewController’s dependency.

Then, the AppDelegate (or SceneDelegate) will be clean, like this example :

self.window?.rootViewController = TransactionsViewControllerFactory.makeTransactionsViewController()
self.window?.makeKeyAndVisible()

References

Original Article — https://arifinfrds.com/2021/10/02/cleaning-appdelegate-or-scenedelegate-using-viewcontrollerfactory/
Head First Design Patterns https://www.oreilly.com/library/view/head-first-design/0596007124/

--

--

Arifin Firdaus
Bootcampers

Software Engineer — iOS | Apple Developer Academy Graduate | Brawijaya University | arifinfrds.com | LinkedIn : linkedin.com/in/arifin