Over the years, the phần mềm di động
industry has grown at a breakneck pace. In the past, mobile applications were mostly small and often contained few screens. While now there are many giant applications, with very complex user interface and business logic
.
For complex applications, the traditional MVC
model reveals many shortcomings such as: View
and Controller
are so closely related that the Model part is almost isolated which makes testing very difficult, ViewController Bigger because both the bussiness logic and the view logic make it difficult to read and understand the code for maintenance and expansion … Clean Architecture
was born to solve the above problems by clearly separating modules based on separate tasks.
Clean Architecture
Clean Architecture
was introduced by Robert C. Martin (aka Uncle Bob) and received great attention from developers. Clean Architecture
is a business architecture that separates business processes from the UI and framework, defining the roles and responsibilities of each layer in its architecture.
The Anatomy of the Clean Architecture
There are many variations of Clean Architecture
, in iOS you can hear about VIPER
or CleanSwift
. When jumping to other platforms like .NET
or Android
even more variants. However, all variants have the same task of separating business processes from the UI and the framework and following the rules of the Clean Architecture
.
Here is a list of components in the architecture:
- View : The interface shows where the interaction between the app and the user occurs, such as Storyboard or XIB.
- Controller : Get actions or events from the view and update it.
- Interactor : The business logic class where the Controller sends requests.
- Presenter : Get feedback from Interactor to send back to Controller.
- Router : The task of navigating the ViewController.
The core of the architecture is the Controller , Interactor , and Presenter . An important thing to note is that the unidirectional Data Flow
architecture means that data will move in a specific flow, which greatly reduces the complexity and ease of management.
How it works:
- Users interact with the View
- Controller receives event from View to send to Interactor .
- Interactor implements business logic and returns result to Presenter
- Presenter reformats the data and then sends it back to the Controller via viewModel
- The controller receives data from the Presenter then updates the view.
Practice
We define the use-case for each respective layer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token keyword">protocol</span> <span class="token builtin">ListProductsDisplayable</span> <span class="token punctuation">:</span> <span class="token keyword">class</span> <span class="token punctuation">{</span> <span class="token comment">// View Controller</span> <span class="token keyword">func</span> <span class="token function">displayFetchedProducts</span> <span class="token punctuation">(</span> with viewModel <span class="token punctuation">:</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">.</span> <span class="token builtin">ViewModel</span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">display</span> <span class="token punctuation">(</span> error <span class="token punctuation">:</span> <span class="token builtin">AppModels</span> <span class="token punctuation">.</span> <span class="token builtin">Error</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">protocol</span> <span class="token builtin">ListProductsBusinessLogic</span> <span class="token punctuation">{</span> <span class="token comment">// Interactor</span> <span class="token keyword">func</span> <span class="token function">fetchProducts</span> <span class="token punctuation">(</span> with request <span class="token punctuation">:</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">.</span> <span class="token builtin">FetchRequest</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">protocol</span> <span class="token builtin">ListProductsPresentable</span> <span class="token punctuation">{</span> <span class="token comment">// Presenter</span> <span class="token keyword">func</span> <span class="token function">presentFetchedProducts</span> <span class="token punctuation">(</span> <span class="token keyword">for</span> response <span class="token punctuation">:</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">.</span> <span class="token builtin">Response</span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">presentFetchedProducts</span> <span class="token punctuation">(</span> error <span class="token punctuation">:</span> <span class="token builtin">DataError</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">protocol</span> <span class="token builtin">ListProductsRoutable</span> <span class="token punctuation">:</span> <span class="token builtin">AppRoutable</span> <span class="token punctuation">{</span> <span class="token comment">// Router</span> <span class="token keyword">func</span> <span class="token function">showProduct</span> <span class="token punctuation">(</span> <span class="token keyword">for</span> id <span class="token punctuation">:</span> <span class="token builtin">Int</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
This is the flow that occurs at viewDidload interactor.fetchProducts > presenter.presentFetchedProducts > controller.displayFetchedProducts.
Controller :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <span class="token keyword">class</span> <span class="token class-name">ListProductsViewController</span> <span class="token punctuation">:</span> <span class="token builtin">UIViewController</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">lazy</span> <span class="token keyword">var</span> interactor <span class="token punctuation">:</span> <span class="token builtin">ListProductsBusinessLogic</span> <span class="token operator">=</span> <span class="token function">ListProductsInteractor</span> <span class="token punctuation">(</span> presenter <span class="token punctuation">:</span> <span class="token function">ListProductsPresenter</span> <span class="token punctuation">(</span> viewController <span class="token punctuation">:</span> <span class="token keyword">self</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> productsWorker <span class="token punctuation">:</span> <span class="token function">ProductsWorker</span> <span class="token punctuation">(</span> store <span class="token punctuation">:</span> <span class="token function">ProductsMemoryStore</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">private</span> <span class="token keyword">lazy</span> <span class="token keyword">var</span> router <span class="token punctuation">:</span> <span class="token builtin">ListProductsRoutable</span> <span class="token operator">=</span> <span class="token function">ListProductsRouter</span> <span class="token punctuation">(</span> viewController <span class="token punctuation">:</span> <span class="token keyword">self</span> <span class="token punctuation">)</span> <span class="token keyword">private</span> <span class="token keyword">var</span> viewModel <span class="token punctuation">:</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">.</span> <span class="token builtin">ViewModel</span> <span class="token operator">?</span> <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function">viewDidLoad</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">viewDidLoad</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> interactor <span class="token punctuation">.</span> <span class="token function">fetchProducts</span> <span class="token punctuation">(</span> with <span class="token punctuation">:</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">.</span> <span class="token function">FetchRequest</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">extension</span> <span class="token builtin">ListProductsViewController</span> <span class="token punctuation">:</span> <span class="token builtin">ListProductsDisplayable</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">displayFetchedProducts</span> <span class="token punctuation">(</span> with viewModel <span class="token punctuation">:</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">.</span> <span class="token builtin">ViewModel</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> viewModel <span class="token operator">=</span> viewModel tableView <span class="token punctuation">.</span> <span class="token function">reloadData</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">display</span> <span class="token punctuation">(</span> error <span class="token punctuation">:</span> <span class="token builtin">AppModels</span> <span class="token punctuation">.</span> <span class="token builtin">Error</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> alertController <span class="token operator">=</span> <span class="token function">UIAlertController</span> <span class="token punctuation">(</span> title <span class="token punctuation">:</span> error <span class="token punctuation">.</span> title <span class="token punctuation">,</span> message <span class="token punctuation">:</span> error <span class="token punctuation">.</span> message <span class="token punctuation">,</span> preferredStyle <span class="token punctuation">:</span> <span class="token punctuation">.</span> alert <span class="token punctuation">)</span> alertController <span class="token punctuation">.</span> <span class="token function">addAction</span> <span class="token punctuation">(</span> <span class="token function">UIAlertAction</span> <span class="token punctuation">(</span> title <span class="token punctuation">:</span> <span class="token string">"OK"</span> <span class="token punctuation">,</span> style <span class="token punctuation">:</span> <span class="token punctuation">.</span> <span class="token keyword">default</span> <span class="token punctuation">,</span> handler <span class="token punctuation">:</span> <span class="token constant">nil</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token function">present</span> <span class="token punctuation">(</span> alertController <span class="token punctuation">,</span> animated <span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> completion <span class="token punctuation">:</span> <span class="token constant">nil</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">extension</span> <span class="token builtin">ListProductsViewController</span> <span class="token punctuation">:</span> <span class="token builtin">UITableViewDelegate</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">tableView</span> <span class="token punctuation">(</span> <span class="token number">_</span> tableView <span class="token punctuation">:</span> <span class="token builtin">UITableView</span> <span class="token punctuation">,</span> didSelectRowAt indexPath <span class="token punctuation">:</span> <span class="token builtin">IndexPath</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">guard</span> <span class="token keyword">let</span> model <span class="token operator">=</span> viewModel <span class="token operator">?</span> <span class="token punctuation">.</span> products <span class="token punctuation">[</span> indexPath <span class="token punctuation">.</span> row <span class="token punctuation">]</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span> router <span class="token punctuation">.</span> <span class="token function">showProduct</span> <span class="token punctuation">(</span> <span class="token keyword">for</span> <span class="token punctuation">:</span> model <span class="token punctuation">.</span> id <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
The controller creates a router and an instance to Interactor through a presenter. Call Interactor in viewDidload
to fetch list product.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <span class="token keyword">struct</span> <span class="token builtin">ListProductsInteractor</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">let</span> presenter <span class="token punctuation">:</span> <span class="token builtin">ListProductsPresentable</span> <span class="token keyword">private</span> <span class="token keyword">let</span> productsWorker <span class="token punctuation">:</span> <span class="token builtin">ProductsWorkerType</span> <span class="token keyword">init</span> <span class="token punctuation">(</span> presenter <span class="token punctuation">:</span> <span class="token builtin">ListProductsPresentable</span> <span class="token punctuation">,</span> productsWorker <span class="token punctuation">:</span> <span class="token builtin">ProductsWorkerType</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> presenter <span class="token operator">=</span> presenter <span class="token keyword">self</span> <span class="token punctuation">.</span> productsWorker <span class="token operator">=</span> productsWorker <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">extension</span> <span class="token builtin">ListProductsInteractor</span> <span class="token punctuation">:</span> <span class="token builtin">ListProductsBusinessLogic</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">fetchProducts</span> <span class="token punctuation">(</span> with request <span class="token punctuation">:</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">.</span> <span class="token builtin">FetchRequest</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> productsWorker <span class="token punctuation">.</span> fetch <span class="token punctuation">{</span> <span class="token keyword">guard</span> <span class="token keyword">let</span> value <span class="token operator">=</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> value <span class="token punctuation">,</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> isSuccess <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> presenter <span class="token punctuation">.</span> <span class="token function">presentFetchedProducts</span> <span class="token punctuation">(</span> error <span class="token punctuation">:</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> error <span class="token operator">?</span> <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">unknownReason</span> <span class="token punctuation">(</span> <span class="token constant">nil</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> presenter <span class="token punctuation">.</span> <span class="token function">presentFetchedProducts</span> <span class="token punctuation">(</span> <span class="token keyword">for</span> <span class="token punctuation">:</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">.</span> <span class="token function">Response</span> <span class="token punctuation">(</span> products <span class="token punctuation">:</span> value <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Inject 1 productsWorker
at Interactor to handle API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <span class="token keyword">struct</span> <span class="token builtin">ListProductsPresenter</span> <span class="token punctuation">:</span> <span class="token builtin">ListProductsPresentable</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">weak</span> <span class="token keyword">var</span> viewController <span class="token punctuation">:</span> <span class="token builtin">ListProductsDisplayable</span> <span class="token operator">?</span> <span class="token keyword">private</span> <span class="token keyword">let</span> currencyFormatter <span class="token punctuation">:</span> <span class="token builtin">NumberFormatter</span> <span class="token keyword">init</span> <span class="token punctuation">(</span> viewController <span class="token punctuation">:</span> <span class="token builtin">ListProductsDisplayable</span> <span class="token operator">?</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> viewController <span class="token operator">=</span> viewController <span class="token keyword">self</span> <span class="token punctuation">.</span> currencyFormatter <span class="token operator">=</span> <span class="token function">NumberFormatter</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> currencyFormatter <span class="token punctuation">.</span> numberStyle <span class="token operator">=</span> <span class="token punctuation">.</span> currency <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">extension</span> <span class="token builtin">ListProductsPresenter</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">presentFetchedProducts</span> <span class="token punctuation">(</span> <span class="token keyword">for</span> response <span class="token punctuation">:</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">.</span> <span class="token builtin">Response</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> viewModel <span class="token operator">=</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">.</span> <span class="token function">ViewModel</span> <span class="token punctuation">(</span> products <span class="token punctuation">:</span> response <span class="token punctuation">.</span> products <span class="token punctuation">.</span> <span class="token builtin">map</span> <span class="token punctuation">{</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">.</span> <span class="token function">ProductViewModel</span> <span class="token punctuation">(</span> id <span class="token punctuation">:</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> id <span class="token punctuation">,</span> name <span class="token punctuation">:</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> name <span class="token punctuation">,</span> content <span class="token punctuation">:</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> content <span class="token punctuation">,</span> price <span class="token punctuation">:</span> currencyFormatter <span class="token punctuation">.</span> <span class="token function">string</span> <span class="token punctuation">(</span> from <span class="token punctuation">:</span> <span class="token function">NSNumber</span> <span class="token punctuation">(</span> value <span class="token punctuation">:</span> <span class="token function">Float</span> <span class="token punctuation">(</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> priceCents <span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">100</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token operator">?</span> <span class="token string">" <span class="token interpolation"><span class="token delimiter variable">(</span> $ <span class="token number">0</span> <span class="token punctuation">.</span> priceCents <span class="token operator">/</span> <span class="token number">100</span> <span class="token delimiter variable">)</span></span> "</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> viewController <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">displayFetchedProducts</span> <span class="token punctuation">(</span> with <span class="token punctuation">:</span> viewModel <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">presentFetchedProducts</span> <span class="token punctuation">(</span> error <span class="token punctuation">:</span> <span class="token builtin">DataError</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Handle and parse error</span> <span class="token keyword">let</span> viewModel <span class="token operator">=</span> <span class="token builtin">AppModels</span> <span class="token punctuation">.</span> <span class="token function">Error</span> <span class="token punctuation">(</span> title <span class="token punctuation">:</span> <span class="token function">NSLocalizedString</span> <span class="token punctuation">(</span> <span class="token string">"products.error.title"</span> <span class="token punctuation">,</span> <span class="token string">"Title for product error"</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> message <span class="token punctuation">:</span> <span class="token function">String</span> <span class="token punctuation">(</span> format <span class="token punctuation">:</span> <span class="token function">NSLocalizedString</span> <span class="token punctuation">(</span> <span class="token string">"products.error.message"</span> <span class="token punctuation">,</span> <span class="token string">"Message for product error"</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> error <span class="token punctuation">)</span> <span class="token punctuation">)</span> viewController <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">display</span> <span class="token punctuation">(</span> error <span class="token punctuation">:</span> viewModel <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Presenter
will format the respone data and call the controller to display it on the View
Model
are encapsulated in an enum and relate only to its own use case.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <span class="token keyword">enum</span> <span class="token builtin">ListProductsModels</span> <span class="token punctuation">{</span> <span class="token keyword">struct</span> <span class="token builtin">FetchRequest</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">struct</span> <span class="token builtin">SearchRequest</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> text <span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token punctuation">}</span> <span class="token keyword">struct</span> <span class="token builtin">Response</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> products <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token builtin">ProductType</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">struct</span> <span class="token builtin">ViewModel</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> products <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token builtin">ProductViewModel</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">struct</span> <span class="token builtin">ProductViewModel</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> id <span class="token punctuation">:</span> <span class="token builtin">Int</span> <span class="token keyword">let</span> name <span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token keyword">let</span> content <span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token keyword">let</span> price <span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Finally, the Router
is responsible for controlling the flow of the application:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token keyword">struct</span> <span class="token builtin">ListProductsRouter</span> <span class="token punctuation">{</span> <span class="token keyword">weak</span> <span class="token keyword">var</span> viewController <span class="token punctuation">:</span> <span class="token builtin">UIViewController</span> <span class="token operator">?</span> <span class="token keyword">init</span> <span class="token punctuation">(</span> viewController <span class="token punctuation">:</span> <span class="token builtin">UIViewController</span> <span class="token operator">?</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> viewController <span class="token operator">=</span> viewController <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">extension</span> <span class="token builtin">ListProductsRouter</span> <span class="token punctuation">:</span> <span class="token builtin">ListProductsRoutable</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">showProduct</span> <span class="token punctuation">(</span> <span class="token keyword">for</span> id <span class="token punctuation">:</span> <span class="token builtin">Int</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> storyboard <span class="token operator">=</span> <span class="token function">UIStoryboard</span> <span class="token punctuation">(</span> name <span class="token punctuation">:</span> <span class="token string">"ShowProduct"</span> <span class="token punctuation">,</span> bundle <span class="token punctuation">:</span> <span class="token constant">nil</span> <span class="token punctuation">)</span> <span class="token keyword">guard</span> <span class="token keyword">let</span> controller <span class="token operator">=</span> storyboard <span class="token punctuation">.</span> <span class="token function">instantiateInitialViewController</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token operator">?</span> <span class="token builtin">ShowProductViewController</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">assertionFailure</span> <span class="token punctuation">(</span> <span class="token string">"Invalid controller for storyboard <span class="token interpolation"><span class="token delimiter variable">(</span> storyboard <span class="token delimiter variable">)</span></span> ."</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> controller <span class="token punctuation">.</span> productID <span class="token operator">=</span> id viewController <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">present</span> <span class="token punctuation">(</span> controller <span class="token punctuation">,</span> animated <span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
router.showProduct(for: productID)
Conclusion
Clean architechture is very flexible, easy to maintain and extend. Although it is more verbose than other architectures, it is necessary to reduce dependency between layers in the application.
Reference link: https://basememara.com/swift-clean-architecture/