Swift UIRefresh Control 在 UITableView 中拖动刷新会导致应用崩溃

Posted

技术标签:

【中文标题】Swift UIRefresh Control 在 UITableView 中拖动刷新会导致应用崩溃【英文标题】:Swift UIRefresh Control Drag to refresh in UITableView causes app crash 【发布时间】:2020-02-18 08:21:52 【问题描述】:

我的 TableView 中有一个 UIRefreshControll。一切正常,但如果我拉得太快,应用程序就会崩溃。 错误:致命错误:索引超出范围

当我从按钮调用函数 refreshData 时,不会出现崩溃。有点奇怪,因为 refreshControll 没有做与调用动作不同的事情。 我希望有人可以帮助我。

private let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(self.refreshData), for: .valueChanged)

if #available(ios 10.0, *) 
                    self.tableView.refreshControl = self.refreshControl
                 else 
                    self.tableView.addSubview(self.refreshControl)
                

@objc private func refreshData() 

    if isRefreshing 
        self.refreshControl.endRefreshing()
        return
    
    isRefreshing = true
    print("refresh")

    guard let url = URL(string: taskURL) else 
        return
    

    let request = URLRequest(url: url)

    urlSessionBackground.dataTask(with: request)  (dataOpt, response, error) in

        if error != nil 
            DispatchQueue.main.async 
                let alert = UIAlertController(title: "Loading Error", message: "No Internet Connection. Please try again later.", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: (action: UIAlertAction!) in
                    self.refreshControl.endRefreshing()
                ))
                self.present(alert, animated: true)
            
            return
        else 
            self.data.removeAll()
            self.userImage.removeAll()
            self.currentData.removeAll()
            self.taskDetails.removeAll()
        

        guard let dataNew = dataOpt else 
            return
        

        let appdata = try? JSONDecoder().decode(TaskList.self, from: dataNew)

        for data in appdata!

              self.data.append(CellData.init(image: UIImage(named: "Profile"), message: data.name, checkImage: data.status))
                self.userImage.append("")

              self.taskDetails.append(TaskDetails.init(status: data.status, assigned: data.assigneUid, time: data.duedateTsUTC, priority: data.priority, desc: data.desc, uid: data.uid))


        

        self.currentData = self.data

        DispatchQueue.main.async 
            self.tableView.reloadData()
            self.searchBar.text = ""
            self.isRefreshing = false
            self.refreshControl.endRefreshing()
        

    .resume()

修复它:使用临时变量来保存数据并在之后使用。删除数据是个问题。

【问题讨论】:

你试过调试它吗?崩溃到底在哪里? @Simon Liebers 如果 isRefreshing self.refreshControl.endRefreshing() //在此处清空您的表数据 return ,您可以尝试清空本节中的表数据吗 @Lu_ 在函数 cellForRowAt indexPath 上。所以在重新加载 TableView @dakrawat 在我的情况下不起作用。 如果你在 cellForRowAt indexPath 上崩溃了,那么它很有可能是由于 array.so 我的建议是在每次调用它时检查数组数据的内容,因为如果 arraydata 之前被更改并以某种方式被删除tableviewReloading 的中间然后它会崩溃你也可以像我之前所说的那样删除所有数组数据,然后重新加载 tableview adata 【参考方案1】:

试试这个

    if error != nil 
        DispatchQueue.main.async 
            let alert = UIAlertController(title: "Loading Error", message: "No Internet Connection. Please try again later.", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: (action: UIAlertAction!) in
                self.refreshControl.endRefreshing()
            ))
            self.present(alert, animated: true)
        
        return
    else 
        if self.data != nil            
           self.data.removeAll()
        
        if self.userImage != nil            
           self.userImage.removeAll()
        
        if self.currentData != nil            
           self.currentData.removeAll()
        
        if self.taskDetails != nil            
           self.taskDetails.removeAll()
        
    

【讨论】:

【参考方案2】:

试试这个

var dataTask: URLSessionDataTask?
let defaultSession = URLSession(configuration: .background)

@objc private func refreshData() 

if isRefreshing 
    self.refreshControl.endRefreshing()
    return

isRefreshing = true
print("refresh")
guard let url = URL(string: taskURL) else 
    return

dataTask?.cancel()
let request = URLRequest(url: url)

dataTask = 
defaultSession.dataTask(with: url)  [weak self](dataOpt, response, error) in 
defer 
  self?.dataTask = nil


if let error = error 
  DispatchQueue.main.async 
            let alert = UIAlertController(title: "Loading Error", message: "No Internet Connection. Please try again later.", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: (action: UIAlertAction!) in
                self.refreshControl.endRefreshing()
            ))
            self.present(alert, animated: true)
        
        return

 else if 
  let data = dataOpt,
  let response = response as? HTTPURLResponse,
  response.statusCode == 200   
        self.data.removeAll()
        self.userImage.removeAll()
        self.currentData.removeAll()
        self.taskDetails.removeAll()      
    let appdata = try? JSONDecoder().decode(TaskList.self, from: data)

    for data in appdata!

          self.data.append(CellData.init(image: UIImage(named: "Profile"), message: data.name, checkImage: data.status))
            self.userImage.append("")

          self.taskDetails.append(TaskDetails.init(status: data.status, assigned: data.assigneUid, time: data.duedateTsUTC, priority: data.priority, desc: data.desc, uid: data.uid))


    

    self.currentData = self.data

    DispatchQueue.main.async 
        self.tableView.reloadData()
        self.searchBar.text = ""
        self.isRefreshing = false
        self.refreshControl.endRefreshing()
    




dataTask?.resume()


【讨论】:

这个 if 块只是为了避免一次又一次地刷新。我不想在那里停止该方法。而且它不起作用。

以上是关于Swift UIRefresh Control 在 UITableView 中拖动刷新会导致应用崩溃的主要内容,如果未能解决你的问题,请参考以下文章

UIRefresh 控件 endRefreshing 不起作用

Scroll Segmented Control(Swift)

Scroll Segmented Control(Swift)

Apple Page Control 示例代码给出黑屏

无法在 Swift 2 中将 TableView @IBOutlet 连接到 ViewController

向 UINavigationBar 添加搜索按钮:Swift