Как показать / повторно использовать один и тот же вид (Alert) в SwiftUI из всех ViewModels в случае ошибки / сообщения? - PullRequest
0 голосов
/ 01 апреля 2020

Я пытался повторно использовать оповещение из 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, почему это так?

Как я могу решить эту проблему, чтобы избежать шаблонного кода?

1 Ответ

1 голос
/ 02 апреля 2020

Необходимо обновить myTest оболочку свойства и принудительно вызвать издатель objectwillchange базового класса.

@Published var myTest : String = "Hello" {
        willSet {
            self.objectWillChange.send()
        }
    }

Примечание: Оболочка свойства @Published не работает в случае наследуемого класса.

Я надеюсь, что это будет исправлено в будущих выпусках, так как objectWillChange.send () - это много шаблонов для поддержки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...