I am struggling here for days now: I have a async
function that get's called onRecieve
from a timer in a LoadingView
. It calls the getData function from the class ViewModel
. Data gets fetched with an HTTP Get Request and compared: if the fetched ID = to the transactionID in my app and the fetched Status = "Success", then the payment is successful.
This is toggled in my observable class. Have a look:
//View Model
@MainActor class ViewModel: ObservableObject {
@Published var fetchedData = FetchedData()
@Published var successfullPayment: Bool = false
@Published var information: String = "Versuch's weiter!"
// Function to fetch Data from the Databank
func getData() {
guard let url = URL(string: getUrl) else {return}
URLSession.shared.dataTask(with: url) { (data, res, err) in
do{
if let data = data {
let result = try JSONDecoder().decode(FetchedData.self, from: data)
DispatchQueue.main.async {
self.fetchedData = result
if self.fetchedData.id == transactionId && self.fetchedData.statuscode == "Success" {
self.successfullPayment = true
print("Payment was successful")
} else {print("Pending ...")}
}
} else {
print("No data")
}
} catch (let error) {
print(error.localizedDescription)
}
}.resume()
}
}
And this is my observing LoadingView
:
struct LoadingView: View {
//Timer
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
@State private var counter = 0
@State var paymentCancelled = false
@ObservedObject var observable: ViewModel
var body: some View {
ZStack {
Image("money")
.resizable()
.aspectRatio(contentMode: .fit)
VStack {
if self.observable.successfullPayment == true{
Text("Thanks you" as String)
.font(.largeTitle)
.fontWeight(.black)
.multilineTextAlignment(.center)
.padding(.top, 100)
} else {
Text("Paying ..." as String)
.font(.largeTitle)
.fontWeight(.black)
.multilineTextAlignment(.center)
.padding(.top, 100)
}
PushView(destination: CancelledView(), isActive: $paymentCancelled) {
Spacer()
}
Button {
paymentCancelled.toggle()
print("payment cancelled!")
} label: {
Label("Abbrechen", systemImage: "nosign")
.padding(.horizontal, 40)
.padding(.vertical, 10.0)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(10)
.font(Font.body.weight(.medium))
}
.padding(.bottom, 50)
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
.onReceive(timer) { time in
if counter == 90 {
timer.upstream.connect().cancel()
print("Timer cancelled")
} else {
ViewModel().getData()
}
counter += 1
}
}
}
But the published var successfullPayment
doesn't update the View. What am I missing here? Has it to do with the async function?
I will focus only on the call to getData()
. Your view is calling the following command:
ViewModel().getData()
This means that you are calling the function on a new instance of the view model. So, the variables fetchedData
and successfullPayment
will be updated on an instance which is not the one being used in the view.
The first step would be to use the same instance that you have in your view:
observable.getData()
Be sure that the view calling LoadingView
has a @StateObject
of type ViewModel
and that you are passing it correctly.