Slather logo

Coverage for "ContainerFactory.swift" : 100.00%

(25 of 25 relevant lines covered)

RouteComposer/Classes/ContainerFactory.swift

1
//
2
// RouteComposer
3
// ContainerFactory.swift
4
// https://github.com/ekazaev/route-composer
5
//
6
// Created by Eugene Kazaev in 2018-2022.
7
// Distributed under the MIT license.
8
//
9
// Become a sponsor:
10
// https://github.com/sponsors/ekazaev
11
//
12
13
import Foundation
14
import UIKit
15
16
/// The `ContainerFactory` protocol should be implemented by the instance that produces any types of the view controllers
17
/// that can be considered as containers (eg: `UINavigationController`, `UITabBarController`, etc)
18
///
19
/// The `Router` uses `ContainerAction.perform(...)` method of a `ContainerAction` and then populates a full stack of the view controllers
20
/// that were built by the associated factories in one go.
21
/// Example: `Router` requires to populate N-view controllers into `UINavigationController`'s stack.
22
public protocol ContainerFactory: AbstractFactory where ViewController: ContainerViewController {
23
24
    // MARK: Associated types
25
26
    /// Type of `UIViewController` that `ContainerFactory` can build
27
    associatedtype ViewController
28
29
    /// `Context` to be passed into `UIViewController`
30
    associatedtype Context
31
32
    // MARK: Methods to implement
33
34
    /// Builds a `UIViewController` that will be integrated into the stack
35
    ///
36
    /// Parameters:
37
    ///   - context: A `Context` instance that is provided to the `Router`.
38
    ///   - coordinator: A `ChildCoordinator` instance.
39
    /// - Returns: The built `UIViewController` instance with the children view controller inside.
40
    /// - Throws: The `RoutingError` if build did not succeed.
41
    func build(with context: Context, integrating coordinator: ChildCoordinator) throws -> ViewController
42
43
}
44
45
// MARK: Default implementation
46
47
public extension ContainerFactory {
48
49
    /// Default implementation does nothing
50
    mutating func prepare(with context: Context) throws {}
36x
51
52
}
53
54
// MARK: Helper methods
55
56
public extension ContainerFactory {
57
58
    /// Builds a `ContainerFactory` view controller.
59
    func build(with context: Context) throws -> ViewController {
7x
60
        try build(with: context, integrating: ChildCoordinator(childFactories: []))
7x
61
    }
7x
62
63
    /// Prepares the `Factory` and builds its `UIViewController`
64
    func execute(with context: Context) throws -> ViewController {
1x
65
        var factory = self
1x
66
        try factory.prepare(with: context)
1x
67
        return try factory.build(with: context)
1x
68
    }
1x
69
70
}
71
72
// MARK: Helper methods where the Context is Any?
73
74
public extension ContainerFactory where Context == Any? {
75
76
    /// Builds a `ContainerFactory` view controller.
77
    func build() throws -> ViewController {
2x
78
        try build(with: nil)
2x
79
    }
2x
80
81
    /// Prepares the `Factory` and builds its `UIViewController`
82
    func execute() throws -> ViewController {
2x
83
        var factory = self
2x
84
        try factory.prepare()
2x
85
        return try factory.build()
2x
86
    }
2x
87
88
}
89
90
// MARK: Helper methods where the Context is Void
91
92
public extension ContainerFactory where Context == Void {
93
94
    /// Builds a `ContainerFactory` view controller.
95
    func build() throws -> ViewController {
1x
96
        try build(with: ())
1x
97
    }
1x
98
99
    /// Prepares the `Factory` and builds its `UIViewController`
100
    func execute() throws -> ViewController {
1x
101
        var factory = self
1x
102
        try factory.prepare()
1x
103
        return try factory.build()
1x
104
    }
1x
105
106
}