Reputation: 63
I am having issues loading data from a GET request with Alamofire in swift to load items into a UITableView
.
I have 2 methods fetchAllBeerOrders
and fetchAllCocktailOrders
which both are working properly and fetching the correct items. The issue I am having is in the viewWillAppear
method where I call both of these fetch methods and reload the tableView. In the order I have it only the items from the fetchAllCocktailOrders
method are loading in the tableView and I have verified by switching the order and getting the items loaded from fetchAllBeerOrders
.
class DrinkOrdersTableViewController: UITableViewController {
var orders: [Order] = []
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Current Orders"
}
override func viewWillAppear(_ animated: Bool) {
fetchAllBeerOrders { orders in
self.orders = orders!
//print("Beer fetch: ", self.orders)
self.tableView.reloadData()
}
fetchAllCocktailOrders { orders in
self.orders = orders!
//print("Cocktail fetch: ", self.orders)
self.tableView.reloadData()
}
}
private func fetchAllCocktailOrders(completion: @escaping([Order]?) -> Void) {
Alamofire.request("http://127.0.0.1:4000/orders", method: .get)
.validate()
.responseJSON { response in
guard response.result.isSuccess else { return completion(nil) }
guard let rawInventory = response.result.value as? [[String: Any]?] else { return completion(nil) }
let currentOrders = rawInventory.compactMap { ordersDict -> Order? in
guard let orderId = ordersDict!["id"] as? String,
let orderStatus = ordersDict!["status"] as? String,
var pizza = ordersDict!["cocktail"] as? [String: Any] else { return nil }
pizza["image"] = UIImage(named: pizza["image"] as! String)
return Order(
id: orderId,
pizza: Pizza(data: pizza),
status: OrderStatus(rawValue: orderStatus)!
)
}
completion(currentOrders)
}
}
private func fetchAllBeerOrders(completion: @escaping([Order]?) -> Void) {
Alamofire.request("http://127.0.0.1:4000/orders", method: .get)
.validate()
.responseJSON { response in
guard response.result.isSuccess else { return completion(nil) }
guard let rawInventory = response.result.value as? [[String: Any]?] else { return completion(nil) }
let currentOrders = rawInventory.compactMap { ordersDict -> Order? in
guard let orderId = ordersDict!["id"] as? String,
let orderStatus = ordersDict!["status"] as? String,
var pizza = ordersDict!["pizza"] as? [String: Any] else { return nil }
pizza["image"] = UIImage(named: pizza["image"] as! String)
return Order(
id: orderId,
pizza: Pizza(data: pizza),
status: OrderStatus(rawValue: orderStatus)!
)
}
completion(currentOrders)
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("Debugging ROWS", orders.count)
return orders.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "order", for: indexPath)
let order = orders[indexPath.row]
cell.textLabel?.text = order.pizza.name
cell.imageView?.image = order.pizza.image
cell.detailTextLabel?.text = "$\(order.pizza.amount) - \(order.status.rawValue)"
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "orderSegue", sender: orders[indexPath.row] as Order)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "orderSegue" {
guard let vc = segue.destination as? OrderViewController else { return }
vc.order = sender as? Order
}
}
}
Im not sure if I need to combine the GET requests into a single request or if my logic on the approach is wrong but I need the tableView to load orders from both fetchAllBeerOrders
and fetchAllCocktailOrders
. Please help
Upvotes: 1
Views: 761
Reputation: 63
Update:
To achieve my goal of loading data from both GET requests I needed to append the data to the orders array with the .append(contentsOf: orders!)
method instead of with self.orders = orders!
. In the viewWillAppear method the second call to fetchCocktailOrders
will always overwrite the contents from the first call to fetchBeerOrders
. Clearly I am a swift rookie!
fetchAllBeerOrders { orders in
//self.orders.append(orders)
self.orders.append(contentsOf: orders!)
self.tableView.reloadData()
}
fetchAllCocktailOrders { orders in
//self.orders.append(orders)
self.orders.append(contentsOf: orders!)
self.tableView.reloadData()
}
This is the correct code.
Upvotes: 0
Reputation: 976
Like Levi Yonder says, it is indeed a problem with the results of your second request replacing the order
, but his provided answer is not optimal.
You have to keep in mind that network requests are asynchronous. This means fetchAllCocktailOrders
can finish before the fetchAllBeerOrders
request is completed. In that case the same problem would occur:
fetchAllCocktailOrders
completes first, appends the data to ordersfetchAllBeerOrders
completes, replaces current batch of data with result of this request.Solution:
fetchAllBeerOrders { orders in
self.orders.append(orders)
self.tableView.reloadData()
}
fetchAllCocktailOrders { orders in
self.orders.append(orders)
self.tableView.reloadData()
}
Upvotes: 1
Reputation: 177
The reason you are having this issue is that fetchAllCocktailOrders
replaces everything in orders
that the fetchAllBeerOrders
initially had fetched, versus appending to.
So viewWillAppear
is calling fetchAllBeerOrders
, which populates orders
, and then fetchAllCocktailOrders
is replacing everything in orders
instead of appending to everything in orders
.
To fix this, when you call the fetchAllCocktailOrders
, append orders
with the contents of what is being returned by the function, instead of replacing:
override func viewWillAppear(_ animated: Bool) {
fetchAllBeerOrders { beerOrders in
self.orders = beerOrders!
//print("Beer fetch: ", self.orders)
self.tableView.reloadData()
}
fetchAllCocktailOrders { coctailOrders in
self.orders.append(coctailOrders)
//print("Cocktail fetch: ", self.orders)
self.tableView.reloadData()
}
}
Upvotes: 0