Skip to content

Commit 18b46b0

Browse files
committed
Update iOS navigation guides and Kotlin/Swift interop notes
1 parent 53e8e09 commit 18b46b0

3 files changed

Lines changed: 96 additions & 4 deletions

File tree

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,30 @@ router.pop() // вернуться назад
9696
router.replace(.signIn) // очистить стек и перейти на авторизацию
9797

9898
```
99-
Роутер удобно получать через @EnvironmentObject, так его не нужно передавать вручную во все экраны.
99+
Как router передается между экранами:
100+
Роутер удобно получать через `@EnvironmentObject`, так его не нужно вручную передавать во все экраны.
101+
- AppRouterHost создаёт и хранит объект `AppRouter`.
102+
- Все экраны внутри этого хоста получают роутер через `environmentObject(router)`.
103+
- SwiftUI автоматически вкладывает объект в иерархию view, так что любой экран, который находится внутри `AppRouterHost`, может использовать его через @`EnvironmentObject`.
100104

105+
В AppRouterHost:
106+
107+
```swift
108+
@ObservedObject private var router = AppRouter<T>()
109+
110+
var body: some View {
111+
NavigationStack(path: $navigationPath) {
112+
routeView(router, rootRoute)
113+
.navigationDestination(
114+
or: T.self,
115+
destination: { routeView(router, $0) }
116+
)
117+
}.environmentObject(router) // роутер передается всем дочерним экранам
118+
}
119+
120+
```
121+
122+
В любом дочернем экране:
101123
```swift
102124
struct AuthScreen: View {
103125
@EnvironmentObject var router: AppRouter<AppRoute>
@@ -108,7 +130,6 @@ struct AuthScreen: View {
108130
}
109131
}
110132
}
111-
112133
```
113134

114135
## AppRouterHost
@@ -173,6 +194,68 @@ struct RootScreenView: View {
173194
В этот момент RootScreenView переключает показ на `MainNavigationView`.
174195
Если пользователь нажимает "Выйти", то срабатывает `LogoutNavigationHookView`, и всё сбрасывается на SignIn.
175196

197+
## LogoutNavigationHookView
198+
199+
В приложениях часто нужно сбросить навигацию при выходе пользователя. Для этого используется LogoutNavigationHookView.
200+
Он оборачивает контент и отслеживает события логаута через logoutHandler. Когда происходит событие логаута, вызывается onLogout(), и можно, например, сбросить стек навигации на экран авторизации.
201+
202+
```swift
203+
import Combine
204+
import MultiPlatformLibrary
205+
import SwiftUI
206+
207+
struct LogoutNavigationHookView<Content: View>: View {
208+
209+
// LogoutNavigationHookView слушает события логаута через logoutHandler.
210+
private var logoutHandler: LogoutHandler = Koin.instance.getLogoutHandler()
211+
212+
let onLogout: () -> Void
213+
let content: () -> Content
214+
215+
init(onLogout: @escaping () -> Void, @ViewBuilder content: @escaping () -> Content) {
216+
self.onLogout = onLogout
217+
self.content = content
218+
}
219+
220+
var body: some View {
221+
content()
222+
.onReceive(
223+
logoutHandler.logoutEvents.toPublisher()
224+
.catch { _ in Empty<KotlinUnit, Never>() }
225+
.assertNoFailure()
226+
) { _ in
227+
228+
// При логауте вызывается onLogout(), которое сбрасывает root.
229+
onLogout()
230+
}
231+
}
232+
}
233+
234+
```
235+
236+
В этом примере вызов `onLogout` приводит к сбросу значения root на .mainFlow(.signIn).
237+
`RootScreenView` реагирует на изменение root и показывает экран авторизации.
238+
239+
```swift
240+
struct RootScreenView: View {
241+
@State private var root: RootScreen = .splash
176242

243+
var body: some View {
244+
LogoutNavigationHookView(onLogout: {
245+
246+
// Сбрасываем стек навигации на экран авторизации
247+
root = .mainFlow(route: .signIn)
248+
}) {
249+
switch root {
250+
case .splash:
251+
SplashScreen(root: $root)
252+
case let .mainFlow(route):
253+
MainNavigationView(initialRoute: route)
254+
}
255+
}
256+
}
257+
}
258+
```
259+
Если мы получаем событие logout на любом экране, весь стек навигации автоматически сбрасывается.
177260

178-
- [Навигяция для UIKit через координаторы (Архив)](./navigation-old.md)
261+
- [Навигация для UIKit через координаторы (Архив)](./navigation-uikit.md)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Навигация
1+
# Навигация UIKit
22

33
В основе навигации лежат координаторы. Каждый координатор покрывает логически связанный блок
44
функционала, который чаще всего состоит из нескольких экранов. При этом между собой они независимы и

learning/kotlin-native/swift-interop.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ LoggerKt.log("Hello from iOS")
2121
```
2222
То есть доступ к функции осуществляется не напрямую, а через сгенерированный класс LoggerKt.
2323

24+
Однако при использовании [SKIE](https://skie.touchlab.co/intro) всё работает так, как ожидается - глобальные функции становятся настоящими глобальными функциями в Swift.
25+
26+
И тогда на swift мы сможем писать так:
27+
```swift
28+
log("Hello from iOS")
29+
```
30+
31+
Подробнее: https://skie.touchlab.co/features/global-functions
32+
2433
## Полезные ссылки:
2534

2635
- [Interoperability with Swift/Objective-C](https://kotlinlang.org/docs/native-objc-interop.html)

0 commit comments

Comments
 (0)