Я пытался повторно использовать оповещение из BaseView (SwiftUI), которое может отображаться всеми моделями представлений в моем проекте, поэтому я могу избежать шаблонного кода.
Для этого я создал два представления (BaseView и BaseLoginView) и две модели представления (BaseViewModel и LoginViewModel)
Я понял, что вы просто не можете создать BaseViewModel и реализовать ObservableObject, потому что все переменные @Published в дочерней ViewModel не будут запускать какие-либо события, поэтому кажется, что Интерфейс ObservableObject должен быть реализован в конечном ViewModel, в этом случае LoginViewModel.
Но это приводит к другой проблеме. BaseView таким образом не может иметь @ObservedObject var baseViewModel: BaseViewModel, потому что BaseViewModel не реализует интерфейс ObservableObject. И @ObservedObject необходим для доступа к логическим привязкам с помощью $
. Это то, что мы уже пробовали:
1 - BaseView
struct BaseView<Content: View>: View {
@ObservedObject var baseViewModel: BaseViewModel
let content: Content
init(vm: BaseViewModel, @ViewBuilder content: () -> Content) {
self.baseViewModel = vm
self.content = content()
}
var body: some View {
VStack {
content
}
.alert(isPresented: self.$baseViewModel.showMessage) {
Alert(title: Text(self.baseViewModel.messageTitle), message: Text(self.baseViewModel.messageText), dismissButton: .default(Text("Okay")))
}
}
}
LoginView -> Создает Просмотреть модель и передать ее в базовое представление
import SwiftUI
struct LoginView: View {
@ObservedObject var loginViewModel: LoginViewModel
@State private var username: String = ""
@State private var password: String = ""
let textFieldHeight = CGFloat(60)
let textFieldPadding = CGFloat(15)
init() {
self.loginViewModel = LoginViewModel()
}
var body: some View {
ZStack {
NavigationView {
BaseView(vm: self.loginViewModel) {
VStack(alignment: .leading, spacing: 20) {
Text(self.loginViewModel.myTest)
}
Button(action: {
self.loginViewModel.login()
}) {
Text("Login")
}
}.navigationBarTitle("", displayMode: .inline)
}
}
}
}
BaseViewModel:
import Foundation
class BaseViewModel : ObservableObject {
@Published var showMessage: Bool = false
@Published var messageTitle : String = ""
@Published var messageText : String = ""
public func showMessage(title: String, text: String) {
self.messageTitle = title
self.messageText = text
self.showMessage = true
}
}
LoginViewModel:
import Foundation
class LoginViewModel : BaseViewModel {
@Published var myTest : String = "Hello"
func login() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.myTest = "Bye"
// self.showMessage(title: "Invalid Data", text: "Please fill all fields!")
}
}
}
По умолчанию ContentView, созданный в новом проекте
import SwiftUI
struct ContentView: View {
var body: some View {
//Text("Hello, World!")
LoginView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Проблема в том, что если я обновляю showMessage, он работает, но изменение только строки myTest на Bye не обновляет представление, оно будет обновляться только в том случае, если я также обновлю значение, опубликованное в BaseViewModel, почему это так?
Как я могу решить эту проблему, чтобы избежать шаблонного кода?