SwiftUI /合并从@Published没有对@ObservedObject的更新

时间:2020-04-27 22:33:07

标签: ios swift swiftui combine observedobject

我有一个登录屏幕,然后是一个概述屏幕。当用户成功登录后,登录响应将发回一个项目列表,我想在后续的概览屏幕上显示该项目列表。

我可以看到响应已成功映射,但是概述视图没有收到@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 个答案:

答案 0 :(得分:1)

您向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

答案 1 :(得分:0)

请尝试更改NavigationLink的初始化,如下NavigationLink(destination: OverviewView(viewModel: self.resultsVM), isActive: $successful) { Text("") }

results

OR

通过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) } } } 作为如下参数

{{1}}