#mvvm #swiftui
#mvvm #swiftui
Вопрос:
В моем приложении SwiftUI у меня есть точка входа следующим образом
@main
struct SomeApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
AppContainerView()
}
}
}
struct AppContainerView: View {
@StateObject var appState = AppState()
var body: some View {
if appState.isLoggedIn amp;amp; appState.hasSeenOnboarding {
TabContainerView()
} else {
LandingView().environmentObject(appState)
}
}
}
Я могу обновить isLoggedIn
вот так…
class AppState: ObservableObject {
var cancellables: [AnyCancellable] = []
private let userService: UserServiceProtocol
init(userService: UserServiceProtocol = UserService()) {
self.userService = userService
subscribeForAuthChanges()
}
func subscribeForAuthChanges() {
userService.authChangeSubject.sink(receiveValue: { [weak self] auth, user in
print(auth)
if user != nil {
self?.isLoggedIn = true
}
}).store(in: amp;cancellables)
}
@Published var isLoggedIn = false
@Published var hasSeenOnboarding = false
}
Но когда дело доходит до hasSeenOnboarding
этого, необходимо установить значение true после завершения какого-либо сетевого вызова в ViewModel в одном из LandingView
дочерних представлений. Я могу сделать что-то вроде этого…
struct ChildView: View {
@EnvironmentObject var appState: AppState
@StateObject var viewModel = ChildViewModel()
var body: some View {
VStack {
//...
}.onReceive($viewModel.networkCallCompleted) { completed in
self.appState.hasSeenOnboarding = completed
}
}
}
Но это не ощущается right…is здесь есть лучший вариант для изменения AppState из дочернего представления / ViewModel при использовании MVVM? Или, возможно, лучший подход?
Ответ №1:
Возможной альтернативой является передача AppState
в ChildViewModel
и выполнение AppState
обновлений непосредственно в модели представления.
struct ParentView: View {
@EnvironmentObject var appState: AppState
var body: some View {
ChildView(viewModel: ChildViewModel(appState: appState))
}
}
struct ChildView: View {
@EnvironmentObject var appState: AppState
@StateObject var viewModel: ChildViewModel
var body: some View {
...
}
}
Примечание
Возможно, вы захотите взглянуть на внедрение зависимостей, чтобы сделать его более чистым. Вот возможный пример: Простое внедрение зависимости с использованием @propertyWrapper.
Комментарии:
1. Спасибо, это работает — хотя, когда я изменяю свойство @Published hasSeenOnboarding на @AppStorage (AppState.hasSeenOnboardingKey) var hasSeenOnboarding: Bool = false, оно по какой-то причине не перезагружает представление
2. @jeh
@AppStorage
следует использовать только в представлении (точно так же, как@State
).