Skip to content

Commit 53e8e09

Browse files
committed
update ios specific onboarding and new swiftUI navigation
1 parent d032f35 commit 53e8e09

4 files changed

Lines changed: 315 additions & 120 deletions

File tree

learning/ios/navigation-old.md

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Навигация
2+
3+
В основе навигации лежат координаторы. Каждый координатор покрывает логически связанный блок
4+
функционала, который чаще всего состоит из нескольких экранов. При этом между собой они независимы и
5+
отвечают только за цепочку переходов внутри себя. Также имеют возможность получать настройку
6+
действия, которое должно быть выполнено после завершения блока ответственности координатора.
7+
8+
## Пример
9+
10+
Предположим, что у нас есть приложение с авторизацией и списком новостей, с которого
11+
можно перейти к детальному просмотру каждой новости и в раздел настроек для конфигурации отображения новостей.
12+
13+
Это разобьётся на 4 координатора:
14+
15+
```mermaid
16+
graph TD
17+
AppCoordinator --> AuthCoordinator
18+
AppCoordinator --> NewsCoordinator
19+
NewsCoordinator --> SettingsCoordinator
20+
```
21+
22+
- AppCoordinator
23+
- Стартовый координатор. Всегда является первой входной точкой, определяет, куда должен выполниться дальнейший переход при запуске приложения
24+
- Если юзер не авторизован - запустит координатор авторизации и в качестве completionHandler-а укажет ему переход на список новостей в случае успешной авторизации
25+
- Если юзер уже авторизован - запустит координатор просмотра списка новостей
26+
- AuthCoordinator
27+
- Запустит процесс авторизации
28+
- Будет совершать переходы по всем требуемым шагам - например ввод логина/пароля, смс-кода, установки никнейма и т.п.
29+
- По итогу успешной авторизации вызовет переданный ему на вход completionHandler.
30+
- NewsCoordinator
31+
- Отвечает за показ списка новостей
32+
- Реализовывает переход в детали конкретной новости внутри этого же координатора
33+
- При переходе в настройки создаёт координатор настроек, в качестве completionHandler-а может передать ему логику обновления своего списка новостей. Если в настройках изменились параметры - обновляет список
34+
- SettingsCoordinator
35+
- Отвечает за работу с экраном настроек
36+
- При завершении работы и применении настроек вызывает completion, чтобы новости обновились
37+
38+
# BaseCoordinator
39+
40+
Чтобы работать с координаторами было проще, используется базовый класс, от которого наследуются
41+
остальные. В директории `Common/Coordinator` вы найдете файлы `CoordinatorProtocol.swift` и `BaseCoordinator.swift`. Первый несет в себе протокол, под который подписан `BaseCoordinator` и описывает обязательные методы и поля:
42+
43+
```swift
44+
protocol Coordinator: AnyObject {
45+
var completionHandler: (()->())? { get }
46+
func start()
47+
func clear()
48+
}
49+
```
50+
51+
По сути он должен иметь ровно три вещи - completionHandler, который вызовется при завершении его логической зоны ответственности. Функцию start, при вызове которой он начинает запускать свой флоу таким образом, каким считает нужным, и функцию clear, которая чистит сам координатор и все дочерние.
52+
53+
Ну а второй несет сам класс базового координатора, который реализует этот протокол:
54+
55+
```swift
56+
class BaseCoordinator: NSObject, Coordinator, UINavigationControllerDelegate {
57+
var childCoordinators: [Coordinator] = []
58+
var completionHandler: (() -> ())?
59+
60+
let window: UIWindow
61+
let factory: SharedFactory
62+
63+
var navigationController: UINavigationController?
64+
65+
init(window: UIWindow, factory: SharedFactory) { ... }
66+
67+
func addDependency<Child>(_ coordinator: Child, completion: (() -> Void)? = nil) -> Child where Child : BaseCoordinator { ... }
68+
69+
func clear() { ... }
70+
71+
//Cases
72+
//1. Initial with window - create NV, etc..
73+
//2. Exists navcontroller,
74+
75+
func start() {
76+
//
77+
}
78+
79+
func beginInNewNavigation(_ controller: UIViewController) -> UINavigationController { ... }
80+
81+
func beginInExistNavigation(_ controller: UIViewController) { ... }
82+
83+
func currentViewController() -> UIViewController { ... }
84+
}
85+
86+
```
87+
88+
Для инициализации необходим window и factory. Также можно указать NavigationController с предыдущего
89+
координатора, для сохранения общей навигации.
90+
91+
:::note
92+
93+
Координаторам нужен factory для доступа к фабрикам фичей из общей библиотеки.
94+
95+
:::
96+
97+
Добавление и удаление зависимостей нужны для корректной очистки связей и памяти при построении
98+
цепочек координаторов.
99+
100+
Также есть вспомогательные методы, которые позволяют получить текущий контроллер -
101+
currentViewController и совершить переход назад - popBack.
102+
103+
:::caution
104+
От проекта к проекту базовый координатор может изменяться, обеспечивая дополнительные нужды проекта.
105+
:::
106+
107+
## AppСoordinator
108+
109+
Теперь когда мы поняли принцип работы координаторов, посмотрим на класс `AppCoordinator`:
110+
111+
```swift
112+
class AppCoordinator: BaseCoordinator {
113+
override func start() {
114+
let vc = UIViewController()
115+
vc.view.backgroundColor = .green
116+
self.window.rootViewController = vc
117+
}
118+
}
119+
```
120+
121+
В данном случае, главный координатор совсем простой - создает контроллер зелёного цвета и делает его главным экраном window.
122+
123+
Теперь посмотрим где происходит создание главного координатора. Идём в `AppDelegate.swift`:
124+
125+
```swift
126+
// ....
127+
128+
// переменная координатора
129+
private (set) var coordinator: AppCoordinator!
130+
131+
func application(_ application: UIApplication,
132+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
133+
134+
//...
135+
136+
// его инициализация
137+
coordinator = AppCoordinator.init(
138+
window: self.window!,
139+
factory: AppComponent.factory
140+
)
141+
// запуск координатора
142+
coordinator.start()
143+
144+
// ....
145+
}
146+
```
147+
148+
Теперь дальнейшая логика переходов зависит от текущего контроллера и действий юзера на нём.
149+
150+
После данного разбора у вас должно сформироваться представление о том, какие подходы мы используем
151+
для реализации навигации в iOS-приложении.
152+
153+
## Материалы
154+
155+
- [Статья - How to use the coordinator pattern in iOS apps](https://www.hackingwithswift.com/articles/71/how-to-use-the-coordinator-pattern-in-ios-apps)
156+
- [Статья - Coordinator Tutorial for iOS: Getting Started](https://www.raywenderlich.com/158-coordinator-tutorial-for-ios-getting-started)
157+
- [Видео-разбор](https://www.youtube.com/watch?v=Pt9TGFzLVzc) использования `ApplicationCoordinator` для навигации между экранами

0 commit comments

Comments
 (0)