SwiftUI / Объединить нет обновлений @ObservedObject от @Published - PullRequest
1 голос
/ 28 апреля 2020

У меня есть экран входа в систему, а затем обзорный экран. Когда пользователь успешно вошел в систему, ответ на вход в систему отправляет обратно список элементов, которые я хочу отобразить на следующем обзорном экране.

Я вижу, что ответ успешно сопоставлен, но обзорный вид не получает любое обновление @ObservedObject. Я мог упустить что-то очевидное, но я просмотрел кучу статей и не смог заставить что-то работать. Любая помощь приветствуется!

Вид входа в систему

import SwiftUI

struct LogonView: View {

    @State private var username: String = ""
    @State private var password: String = ""
    @State private var inputError: Bool = false
    @State private var errorMessage: String = ""
    @State private var loading: Bool? = false
    @State private var helpShown: Bool = false
    @State private var successful: Bool = false


    //MARK:- UIView
    var body: some View {

        NavigationView {

            VStack {

                VStack {
                    TextField("Username", text: $username)
                        .padding(.horizontal)
                        .disabled(loading! ? true : false)
                    Rectangle()
                        .frame(height: 2.0)
                        .padding(.horizontal)
                        .foregroundColor(!inputError ? Color("SharesaveLightGrey") : Color("SharesaveError"))
                        .animation(.easeInOut)
                }.padding(.top, 80)


                VStack {
                    SecureField("Password", text: $password)
                        .padding(.horizontal)
                        .disabled(loading! ? true : false)
                    Rectangle()
                        .frame(height: 2.0)
                        .padding(.horizontal)
                        .foregroundColor(!inputError ? Color("SharesaveLightGrey") : Color("SharesaveError"))
                        .animation(.easeInOut)
                }.padding(.top, 40)



                if (inputError) {
                    HStack {
                        Text(errorMessage)
                            .padding(.top)
                            .padding(.horizontal)
                            .foregroundColor(Color("SharesaveError"))
                            .animation(.easeInOut)
                            .lineLimit(nil)
                            .font(.footnote)
                        Spacer()
                    }
                }


                SharesaveButton(action: {self.submit(user: self.username, pass: self.password)},
                       label: "Log on",
                       loading: $loading,
                       style: .primary)
                    .padding(.top, 40)
                .animation(.interactiveSpring())


                NavigationLink(destination: OverviewView(), isActive: $successful) {
                    Text("")
                }

                Spacer()

            }
            .navigationBarTitle("Hello.")
            .navigationBarItems(
                trailing: Button(action: { self.helpShown = true }) {
                     Text("Need help?").foregroundColor(.gray)
                })
                .sheet(isPresented: $helpShown) {
                    SafariView( url: URL(string: "http://google.com")! )
            }

        }
    }


    //MARK:- Functions
    private func submit(user: String, pass: String) {

        loading = true
        inputError = false
        let resultsVM = ResultsViewModel()

        resultsVM.getGrants(user: user, pass: pass,

        successful: { response in
            self.loading = false
            if ((response) != nil) { self.successful = true }
        },

        error: { error in
            self.inputError = true
            self.loading = false
            self.successful = false
            switch error {
            case 401:
                self.errorMessage = "Your credentials were incorrect"
            default:
                self.errorMessage = "Something went wrong, please try again"
            }
        },

        failure: { fail in
            self.inputError = true
            self.loading = false
            self.successful = false
            self.errorMessage = "Check your internet connection"
        })
    }
}

Просмотр результатов Модель

import Foundation
import Moya
import Combine
import SwiftUI

class ResultsViewModel: ObservableObject {

    @Published var results: Results = Results()

    func getGrants(
        user: String,
        pass: String,
        successful successCallback: @escaping (Results?) -> Void,
        error errorCallback: @escaping (Int) -> Void,
        failure failureCallback: @escaping (MoyaError?) -> Void
        )
    {
        let provider = MoyaProvider<sharesaveAPI>()

        provider.request(.getSharesave(username: user, password: pass)) { response in

            switch response.result {

            case .success(let value):
                do {
                    let data = try JSONDecoder().decode(Results.self, from: value.data)
                    self.results = data
                    successCallback(data)

                } catch {
                    let errorCode = value.statusCode
                    errorCallback(errorCode)
                }

            case .failure(let error):
                failureCallback(error)
            }
        }
    }

}

Обзор Просмотр

import SwiftUI
import Combine

struct OverviewView: View {

    @ObservedObject var viewModel: ResultsViewModel = ResultsViewModel()

    var body: some View {

        let text = "\(self.viewModel.results.market?.sharePrice ?? 0.00)"

        return List {
            Text(text)
        }           
    }
}

Ответы [ 2 ]

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

Вы отправили запрос в один экземпляр ResultsViewModel

private func submit(user: String, pass: String) {

    loading = true
    inputError = false
    let resultsVM = ResultsViewModel() // << here 

, пытаясь прочитать данные из другого экземпляра ResultsViewModel

struct OverviewView: View {

    @ObservedObject var viewModel: ResultsViewModel = ResultsViewModel() // << here

, но это должно быть один экземпляр , поэтому измените его следующим образом

1) в OverviewView

struct OverviewView: View {

    @ObservedObject var viewModel: ResultsViewModel // expects injection 

2) в LogonView

struct LogonView: View {
    @ObservedObject var resultsViewModel = ResultsViewModel() // created once

и введите то же самое экземпляр для OverviewView

NavigationLink(destination: OverviewView(viewModel: self.resultsViewModel), isActive: $successful) {
    Text("")
}

и для отправки

    private func submit(user: String, pass: String) {

        loading = true
        inputError = false
        let resultsVM = self.resultsViewModel // use created
0 голосов
/ 28 апреля 2020

Пожалуйста, попробуйте после изменения инициализировать OverviewView, как показано ниже в NavigationLink

NavigationLink(destination: OverviewView(viewModel: self.resultsVM),
                                         isActive: $successful) {
       Text("")
}

ИЛИ

передать results в OverviewView в качестве аргумента, как показано ниже

NavigationLink(destination: OverviewView(results: self.resultsVM.results),
                                         isActive: $successful) {
       Text("")
}
.....
struct OverviewView: View {
    let results: Results
    var body: some View {
        let text = "\(self.results.market?.sharePrice ?? 0.00)"
        return List {
           Text(text)
        }           
    }
}
...