RealTime Reload UITableview没有"Index out of Range"swift

leo*_*019 5 real-time uitableview ios swift swift3

我正试图每秒重新加载我的tableview.我现在重新加载tableview对象,但由于我Order在重新加载之前清除数组,因为索引超出范围而崩溃.

这是我目前的代码

 var orders = [Order]()

 override func viewDidLoad() {
    super.viewDidLoad()

    // table stuff
    tableview.dataSource = self
    tableview.delegate = self

    // update orders
    var timer = Timer.scheduledTimer(timeInterval: 4, target: self, selector: "GetOrders", userInfo: nil, repeats: true)

    GetOrders()

}

 func numberOfSections(in tableView: UITableView) -> Int {
    if orders.count > 0 {
        self.tableview.backgroundView = nil
        self.tableview.separatorStyle = .singleLine
        return 1
    }

    let rect = CGRect(x: 0,
                      y: 0,
                      width: self.tableview.bounds.size.width,
                      height: self.tableview.bounds.size.height)
    let noDataLabel: UILabel = UILabel(frame: rect)

    noDataLabel.text = "no orders"
    noDataLabel.textColor = UIColor.white
    noDataLabel.textAlignment = NSTextAlignment.center
    self.tableview.backgroundView = noDataLabel
    self.tableview.separatorStyle = .none


    return 0
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return orders.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     let cell = tableView.dequeueReusableCell(withIdentifier: "OrderCell", for: indexPath) as! OrderCell

    let entry = orders[indexPath.row]

    cell.DateLab.text = entry.date
     cell.shopNameLab.text = entry.shopname
    cell.shopAddLab.text = entry.shopaddress
    cell.nameClientLab.text = entry.clientName
    cell.clientAddLab.text = entry.ClientAddress
    cell.costLab.text = entry.Cost
    cell.perefTimeLab.text = entry.PerferTime
    cell.Shopimage.hnk_setImage(from: URL(string: entry.Logo))

    return cell
}
Run Code Online (Sandbox Code Playgroud)

这是我如何从API获取数据:

func GetOrders (){

orders = []
// get data by Alamofire

       let info = Order(shopname: shopname, shopaddress: shopaddr,
 clientName: cleintName,ClientAddress: clientAddres, PerferTime: time,
Cost: subtotal , date : time , Logo : logoString ,id : id)

      self.orders.append(info)

  // some if statements 
   DispatchQueue.main.async {
                self.tableview.reloadData()

            }
Run Code Online (Sandbox Code Playgroud)

如果范围超出索引,则返回此处

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let order =  orders[indexPath.row]
        guard orders.count > indexPath.row else {
            print("Index out of range")
            return
        }

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        var viewController = storyboard.instantiateViewController(withIdentifier: "viewControllerIdentifer") as! OrderDetailsController
        viewController.passedValue = order.id
        self.present(viewController, animated: true , completion: nil)


}
Run Code Online (Sandbox Code Playgroud)

Gok*_*kul 7

我不知道它是否有效,但不过试一试.

  1. 我认为你在从API获取数据之前清空你的orders(orders = [])数组,同时你之前的调用尝试重新加载tableview index out of range.
  2. 更改您的GetOrders()函数,如下所示

    func GetOrders (){
    
       //orders = [] remove this line
       // get data by Alamofire
    
       // some if statements 
       DispatchQueue.main.async {
          //empty your array in main queue most importantly just after getting data from API and just before appending new data's
          orders = [] 
          let info = Order(shopname: shopname, shopaddress: shopaddr,  clientName: cleintName,ClientAddress: clientAddres, PerferTime: time,
             Cost: subtotal , date : time , Logo : logoString ,id : id)
          self.orders.append(info)
          self.tableview.reloadData()
     }
    
    Run Code Online (Sandbox Code Playgroud)

**在从API获取数据之后,在添加新数据之前,最重要的是清空主队列中的数组

  1. 如果它无法解决您的问题,As @ o15a3d4l11s2表示确保GetOrders()只有在收到上一次通话的响应后才会调用该功能

     override func viewDidLoad() {
        super.viewDidLoad()
        tableview.dataSource = self
        tableview.delegate = self
        GetOrders()
     }
    
     func GetOrders (){
    
       //orders = [] remove this line
       // get data by Alamofire
    
       // some if statements 
       DispatchQueue.main.async {
          //empty your array in main queue most importantly just after getting data from API and just before appending new data's
          orders = [] 
          let info = Order(shopname: shopname, shopaddress: shopaddr,  clientName: cleintName,ClientAddress: clientAddres, PerferTime: time,
             Cost: subtotal , date : time , Logo : logoString ,id : id)
          self.orders.append(info)
          self.tableview.reloadData()
    
          Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self. getOrder), userInfo: nil, repeats: false)
     }
    
    Run Code Online (Sandbox Code Playgroud)


o15*_*1s2 6

这是一个逻辑提议,用于刷新订单并远离超出限制的异常 - 让我们getOrders()只在完成时调度自己的下一个调用.这是一个例子:

func getOrders() {
    asyncLoadOrders(onComplete: { loadedOrders
        self.orders = loadedOrders
        self.tableView.reloadData()
        Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self. getOrder), userInfo: nil, repeats: false)
    }
}
Run Code Online (Sandbox Code Playgroud)

这个逻辑的想法是在订单真正加载后一秒钟,然后才会调用下一个getOrders.

请注意,可能需要包装表的重载(如在您的示例中) DispatchQueue.main.async


Sub*_*n P 4

你之所以得到这个结果是indexOutOfRange因为你根据 api 响应每 4 秒修改一次数组。tableview dataSource同时,您尝试访问同一数组中的数据。

变化:1:

tableView DataSource为 api 响应创建一个单独的数组。

func getOrders() {

    var tempOrdersList = [Order]()


   // get data by Alamofire

   let info = Order(shopname: shopname, shopaddress: shopaddr, clientName: cleintName,ClientAddress: clientAddres, PerferTime: time,Cost: subtotal , date : time , Logo : logoString ,id : id)

   tempOrdersList.append(info)

  // some if statements 
   DispatchQueue.main.async {

        //Assign temporary array to class variable, which you are using as tableview data source. 

        self.orders = tempOrdersList

        self.tableview.reloadData()
   }
}
Run Code Online (Sandbox Code Playgroud)

变化2:

不要简单地每 4 秒触发一次 api。一旦收到 api 的响应就安排计时器。

func getOrders() {

        var tempOrdersList = [Order]()


       // get data by Alamofire

       let info = Order(shopname: shopname, shopaddress: shopaddr, clientName: cleintName,ClientAddress: clientAddres, PerferTime: time,Cost: subtotal , date : time , Logo : logoString ,id : id)

       tempOrdersList.append(info)

      // some if statements 
       DispatchQueue.main.async {

            //Assign temporary array to class variable, which you are using as tableview data source. 

            self.orders = tempOrdersList

            self.tableview.reloadData()


             timer =  Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(self. getOrder), userInfo: nil, repeats: false)

       }
  }


 // Invalidate the timer at the view controller deinit
 deinit {
    timer.invalidate()
 }
Run Code Online (Sandbox Code Playgroud)