【问题标题】:Swift- Problem making multiple GET requests with AlamofireSwift-使用 Alamofire 发出多个 GET 请求时出现问题
【发布时间】:2019-09-08 02:17:27
【问题描述】:

我在使用 Alamofire 快速从 GET 请求加载数据以将项目加载到 UITableView 时遇到问题。

我有 2 个方法 fetchAllBeerOrdersfetchAllCocktailOrders 都可以正常工作并获取正确的项目。我遇到的问题是在viewWillAppear 方法中,我调用这两个获取方法并重新加载tableView。按照我的顺序,只有fetchAllCocktailOrders 方法中的项目加载到tableView 中,我通过切换顺序并从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 来加载来自 fetchAllBeerOrdersfetchAllCocktailOrders 的订单。请帮忙

【问题讨论】:

    标签: ios arrays swift api alamofire


    【解决方案1】:

    更新:

    为了实现从两个 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()
            }
    

    这是正确的代码。

    【讨论】:

      【解决方案2】:

      就像 Levi Yonder 所说,您的第二个请求替换 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()
      }
      

      【讨论】:

      • 我确实在您发表评论之前尝试过这种方法:/。我以为我可以在每次调用 fetchAll...Orders 时附加订单的内容,但我仍然在两个附加行上收到错误 Cannot convert value of type '[Order]' to expected argument type 'Order' (self.orders.append(orders!))
      • 我整天都在纠结这个问题,你知道是否有另一种好方法可以将这种类型的数据附加到数组中?
      【解决方案3】:

      您遇到此问题的原因是 fetchAllCocktailOrders 替换了 ordersfetchAllBeerOrders 最初获取的所有内容,而不是附加到。

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

      【讨论】:

      • 我已经尝试过这种方法,但出现了预期的参数类型Order。如图:(i.imgur.com/v1uaurL.png)。我相信这是因为它需要一个orders 类型的数组。我认为附加数据是正确的,但我知道如何去做。
      猜你喜欢
      • 2018-01-18
      • 2022-06-17
      • 1970-01-01
      • 2021-12-01
      • 2014-04-15
      • 2014-07-06
      • 2016-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多