| OLD | NEW |
| 1 # Application Steps | 1 # iOS Chrome Architecture |
| 2 | 2 |
| 3 ----- | 3 `/ios/clean/` houses a revised and updated architecture for iOS Chrome's UI. iOS |
| 4 **The files in this directory are only used in the new architecture for iOS | 4 is in the process of migrating into this new architecture. During this process, |
| 5 Chrome** | 5 code in `/ios/clean` should not depend on code in `ios/chrome/browser/ui`, or |
| 6 ----- | 6 vice-versa; instead code that is shared between the two will be moved into |
| 7 `ios/shared`. |
| 8 |
| 9 This document is a general overview of the fundamental concepts of the new |
| 10 architecture. More specific documentation is located alongside the |
| 11 implementations. |
| 12 |
| 13 [TOC] |
| 14 |
| 15 ## Goals and core principles. |
| 16 |
| 17 The goals of the new architecture, briefly, are to: |
| 18 |
| 19 * Allow for radical user interface experimentation and changes. |
| 20 * Make development and maintenance of features easier. |
| 21 * Cut the Gordian knots of the existing architecture, removing the need for |
| 22 [unmaintainable monster classes](/ios/chrome/browser/ui/BrowserViewController.
mm) |
| 23 that accrete functionality. |
| 24 * Keep up with the evolution if iOS by providing a structure in which the |
| 25 affordances provided by Cocoa Touch can be used without radical changes. |
| 26 |
| 27 In order to meet these goals, the new architecture is designed according to |
| 28 these three core principles: |
| 29 |
| 30 * **Strong Decoupling.** Components of the browser, especially UI components, |
| 31 should not depend on other components explicitly. Where components interact, |
| 32 they should do so through protocols or other abstractions that prevent |
| 33 tight coupling. |
| 34 * **Strong Encapsulation.** A complement to decoupling is encapsulation. |
| 35 Components of the browser should expose little specifics about their |
| 36 implementation or state. Public APIs should be as small as possible. |
| 37 Architectural commonalities (for example, the use of a common superclass for |
| 38 coordinators) will mean that the essential interfaces for complex components |
| 39 can be both small and common across many implementations. Overall the |
| 40 combination of decoupling and encapsulation means that components of |
| 41 Chrome can be rearranged or removed without impacting the rest of the |
| 42 application. |
| 43 * **Separation of layers.** Objects should operate at a specific layer, and |
| 44 their interactions with objects in other layers should be well-defined. We |
| 45 distinguish model, coordinator, and UI layers. |
| 46 |
| 47 ## Structure. |
| 48 |
| 49 ### View controllers. |
| 50 |
| 51 Since this is an iOS application, view controllers remain a fundamental building |
| 52 block of the user interface. However, the scope of a view controller’s |
| 53 responsibilities are strongly constrained. View controllers are responsible for |
| 54 the display and user interactions of a specific piece of user interface. They |
| 55 may contain, or be contained in, other view controllers in order to compose the |
| 56 complete UI that a user interacts with. |
| 57 |
| 58 For example, when viewing a web page in a Chrome tab, the web page contents, the |
| 59 toolbar above the page, and the location bar in the toolbar are each separate |
| 60 view controllers, and a fourth view controller is responsible for composing them |
| 61 together. View controllers do not directly interact with each other or with any |
| 62 model-layer services. |
| 63 |
| 64 ### Coordinators. |
| 65 |
| 66 Since view controllers are heavily encapsulated, another object is responsible |
| 67 for creating them and connecting them to other objects. This object is a |
| 68 coordinator, and in this architecture all coordinators are subclasses of |
| 69 [BrowserCoordinator](/ios/shared/chrome/browser/ui/coordinators/). Coordinators |
| 70 exist in a hierarchy, roughly parallel to the view controller hierarchy; each |
| 71 coordinator can have multiple child coordinators, and there is a single root |
| 72 coordinator that is created when the application launches. |
| 73 |
| 74 The primary role of coordinators is to create and configure their view |
| 75 controller, connect it to a mediator and/or a dispatcher (see below), and to |
| 76 handle the creation and lifecycle of any child view controllers. Coordinators |
| 77 shouldn’t directly interact with model-layer services, and should contain |
| 78 little if any “business logic”. |
| 79 |
| 80 ### Mediators. |
| 81 |
| 82 Mediators encapsulate the interactions between the model layer and the user |
| 83 interface. They are created by coordinators and are handed connections to any |
| 84 model-layer services they need, as well as to a “consumer” which they will |
| 85 push user interface configuration and updates into. |
| 86 |
| 87 The consumer is typically a view controller, and there is a consumer protocol |
| 88 defined as part of the UI layer that the view controller adopts for this |
| 89 purpose. A view controller that integrates UI updates from multiple model |
| 90 services may be consuming from multiple mediators and may thus implement |
| 91 multiple consumer protocols. |
| 92 |
| 93 Mediators can be either Objective-C or C++ objects, and there isn't a universal |
| 94 superclass for them. |
| 95 |
| 96 ### Service Objects. |
| 97 |
| 98 Coordinators are created with access to a number of “service objects” that they |
| 99 may connect to mediators and view controllers. By default a coordinator passes |
| 100 pointers to all of these objects into their children. |
| 101 |
| 102 The inventory of service objects includes: |
| 103 |
| 104 * **[WebStateList:](/ios/chrome/browser/web_state_list/)** An observable, |
| 105 mutable, ordered collection of [WebState](/ios/public/web_state/)s. A WebState |
| 106 is the model-layer representation of a browser tab. |
| 107 |
| 108 * **BrowserState:** The [ChromeBrowserState](/ios/chrome/browser/chrome_browser/
state/) |
| 109 object as used in the old architecture. |
| 110 |
| 111 * **[Dispatcher:](/ios/shared/chrome/browser/ui/commands/)** A decoupled |
| 112 interface over which application-level method calls may be made; see below. |
| 113 |
| 114 * **[Broadcaster:](/ios/shared/chrome/browser/ui/broadcaster)** A decoupled |
| 115 interface over which some properties of the user interface may be observed. |
| 116 |
| 117 Some of these service objects are contained inside a [Browser](/ios/shared/chrom
e/browser/ui/browser_list) |
| 118 object, which represents a collection of user tabs, equivalent to a window on |
| 119 desktop platforms. |
| 120 |
| 121 The Dispatcher merits special discussion. The role of the dispatcher is to |
| 122 opaquely route Objective-C method calls. The dispatcher can register objects to |
| 123 handle specific method calls, or an entire protocol. These protocols are |
| 124 conventionally called [‘commands’](/ios/clean/chrome/browser/ui/commands/). |
| 125 |
| 126 Coordinators typically register themselves or the mediators they own to handle |
| 127 commands related to the area of their responsibility. The dispatcher is handed |
| 128 into the view controller that a coordinator creates in the guise of a generic |
| 129 Objective-C object that conforms to the command protocols that the view |
| 130 controller needs. This allows the view controller to call methods on objects |
| 131 that its coordinator doesn’t directly know about. |
| 132 |
| 133 ## Strictures. |
| 134 |
| 135 Within this basic structure, and given the overall principles of decoupling, |
| 136 encapsulation, and separation of layers, there are a number of restrictions that |
| 137 all of these classes of objects should adhere to. |
| 138 |
| 139 ### View Controllers |
| 140 |
| 141 * Cannot directly create or interact with any other specific classes of view |
| 142 controllers. View controllers that contain other view controllers should have |
| 143 public properties or methods for these embedded view controllers to be |
| 144 provided; internally they are limited to adding, removing, positioning, and |
| 145 resizing any such view controllers. |
| 146 |
| 147 * Cannot depend on any model-layer objects or types. |
| 148 |
| 149 * Should only operate on the main thread. |
| 150 |
| 151 * Should not be their own transitioning delegates; an object from the |
| 152 coordinator layer (usually the coordinator) should handle that. |
| 153 |
| 154 * Should handle action methods for their own UI, or, if appropriate, have the |
| 155 command-handling object they are given (a pointer to the dispatcher) be the |
| 156 target for control actions. |
| 157 |
| 158 * Should only take input from other parts of the application by having them |
| 159 pushed over the consumer interface (or interfaces). |
| 160 |
| 161 * Should only send messages to the rest of the application directly via the |
| 162 dispatcher. |
| 163 |
| 164 ### The UI layer |
| 165 |
| 166 View controllers, the consumer protocols they adopt, and associated classes and |
| 167 assets constitute the “UI layer” of the application, and it is a separate source |
| 168 set in the gn configurations. The UI layer should have no dependencies on |
| 169 coordinators, mediators, or model objects. |
| 170 |
| 171 ### Coordinators |
| 172 |
| 173 * Should only pass a minimal set of service objects into mediators or other |
| 174 objects that require them. Rather than passing a `Browser` or `BrowserState`, |
| 175 they should pass specific services or sub-objects. Rather than passing the |
| 176 Dispatcher, they should cast it into an `i`d object that conforms to the |
| 177 protocol(s) the object requires. |
| 178 |
| 179 * Should only handle command method whose execution is mostly a matter of |
| 180 creating, starting, or stopping other coordinators. Interactions with |
| 181 model-layer objects should be handled by mediators. Coordinators can have |
| 182 methods dispatch to their mediator. |
| 183 |
| 184 * Should only operate on the main thread. |
| 185 |
| 186 * If custom view controller presentation or animation is required, the |
| 187 coordinator can be the presented view controller’s transitioning delegate, or |
| 188 it can create a helper object for that. |
| 189 |
| 190 ### Mediators |
| 191 |
| 192 * Should have any services they need passed into them by the coordinator. They |
| 193 shouldn’t depend on singletons, or on aggregate service objects such as |
| 194 `BrowserState`. |
| 195 |
| 196 * Can communicate with their consumer _only_ over the consumer interface and |
| 197 _only_ on the main thread. It is the mediator’s responsibility to manage any |
| 198 model updates that occur on other threads and consolidate them into updates |
| 199 sent to the consumer on the main thread. |
| 200 |
| 201 * Can only send Foundation value types, collections, or data classes containing |
| 202 them to their consumer. |
| 203 |
| 204 * Cannot expose any kind of delegate interface for the consumer to call. |
| 205 Mediators push updates to consumers, and view controllers call command methods |
| 206 to induce model changes. |
| 207 |
| 208 ### Dispatchers |
| 209 |
| 210 * Should only be used for "command-ish" methods. The dispatcher shouldn’t be |
| 211 used to implement what are functionally delegation, observation, or |
| 212 notification relationships. Other tools (such as the Broadcaster, and |
| 213 model-layer observers) exist for those purposes. |
| 214 |
| OLD | NEW |