Swift - проблема с выполнением нескольких запросов GET с Alamofire - PullRequest
0 голосов
/ 17 апреля 2019

У меня проблемы с загрузкой данных из GET-запроса с помощью Alamofire в быстром режиме для загрузки элементов в UITableView.

У меня есть 2 метода fetchAllBeerOrders и fetchAllCocktailOrders, которые оба работают правильно и выбирают нужные элементы. Проблема, с которой я сталкиваюсь, заключается в методе viewWillAppear, где я вызываю оба эти метода выборки и перезагружаю tableView. В том порядке, в котором он у меня есть, в tableView загружаются только элементы из метода fetchAllCocktailOrders, и я проверил, изменив порядок и получив элементы, загруженные из 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
        }
    }
}

Я не уверен, нужно ли мне объединять запросы GET в один запрос или моя логика в подходе неверна, но мне нужен tableView для загрузки ордеров как из fetchAllBeerOrders, так и fetchAllCocktailOrders. Пожалуйста, помогите

Ответы [ 3 ]

1 голос
/ 17 апреля 2019

Как говорит Леви Йондер, это действительно проблема с результатами вашего второго запроса о замене order, но его ответ не является оптимальным.

Вы должны иметь в виду, что сетевые запросы являются асинхронными. Это означает, что fetchAllCocktailOrders может завершить до запроса fetchAllBeerOrders. В этом случае возникнет та же проблема:

  1. Запрашивает огонь одновременно
  2. fetchAllCocktailOrders завершается первым, добавляет данные к заказам
  3. fetchAllBeerOrders завершает, заменяет текущий пакет данных результатом этого запроса.

Решение:

fetchAllBeerOrders { orders in
    self.orders.append(orders)
    self.tableView.reloadData()
}

fetchAllCocktailOrders { orders in
    self.orders.append(orders)
    self.tableView.reloadData()
}
0 голосов
/ 18 апреля 2019

Обновление:

Чтобы достичь цели загрузки данных из обоих запросов GET, мне нужно было добавить данные в массив заказов с помощью метода .append(contentsOf: orders!) вместо self.orders = orders!. В методе viewWillAppear второй вызов fetchCocktailOrders всегда будет перезаписывать содержимое первого вызова на fetchBeerOrders. Очевидно, я быстрый новичок!

        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()
        }

Это правильный код.

0 голосов
/ 17 апреля 2019

Причина, по которой вы столкнулись с этой проблемой, заключается в том, что fetchAllCocktailOrders заменяет все в orders, которое изначально fetchAllBeerOrders извлек, вместо добавления.

Итак, viewWillAppear вызывает fetchAllBeerOrders, что заполняет orders, а затем fetchAllCocktailOrders заменяет все в orders вместо добавления ко всему в orders.

Чтобы исправить это, при вызове fetchAllCocktailOrders добавьте orders с содержимым того, что возвращается функцией, вместо замены:

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()
        }

    }
...