When I add a product to the cart, it calculates the total price without changing the amount of the product in the cart.
This is how I add products to the cart:
@Published var cartProducts = [CartProduct]()
private let httpDownloader = HttpDownloader()
@Published var cartItemCount = 0
@Published var totalAmount: Double = 0
func getUserProducts() {
httpDownloader.fetchUserProducts() { (result) in
switch result {
case .success(let cartProducts):
if let cartProducts = cartProducts {
DispatchQueue.main.async {
self.cartProducts = cartProducts
}
}
case .failure(let error):
print("Error fetching products: (error)")
}
}
}
func addProductToCart(id: Int, quantity: Int) {
httpDownloader.addProductToCart(productId: id, quantity: quantity) { result in
switch result {
case .success:
DispatchQueue.main.async {
self.getUserProducts()
print(self.cartProducts.first?.quantity ?? 0)
self.calculateTotalPrice(products: self.cartProducts)
}
case .failure(let error):
print("Error fetching products: (error)")
}
}
}
For example, the amount of product in the cart is currently 4. When I add an item to the cart, 4 is printed on the screen and the price is calculated accordingly. Then, when I send a request to Postman, I see that the amount of products in the cart has increased to 5.
I think the problem occurs because the amount of items in the cart is updated exactly and the app calculates the total price before it is captured.
Github repository address of the project: https://github.com/mehmetozkn/swiftui-computer-store-app
2
Answers
I solved the problem by calling the calculateTotal function here
This is an async issue, not a SwiftUI issue.
Your
getUserProducts()
function starts a network request, and then returns immediately before it completes. YouraddProductToCart()
function callsgetUserProducts()
, and expects the results to be available as soon asgetUserProducts()
returns. Async code doesn’t work that way.I suggest reading up on async await and rewriting your function using async.
Alternatively you could rewrite your
getUserProducts()
to take a completion handler.Fixing your whole app is more than I’m ready to take on, but here are some steps towards using async:
Rewrite your getUserProducts function to be async:
For that to work you’ll also need to rewrite your fetchUserProducts() function to also be async:
And then in your
addProductToCart
function, you could wrap your call togetUserProducts
in aTask
:Edit:
If instead you want to use completion handlers, a naive rewrite of your
getUserProducts()
function might look like this:And then call it like this:
(I say that’s a a naive rewrite because your code puts the results of the network calls into global variables, which is not great practice. It should really be rewritten to pass the resulting array (or an error) to the completion handler, and let the completion handler save the results as needed.)