
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

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
Head First Design Patterns https://www.oreilly.com/library/view/head-first-design/0596007124/