异步任务后插入UIViewtable

时间:2017-04-18 15:15:05

标签: swift uitableview asynchronous swift3

我正在尝试在我解析来自URL的JSON数据的异步任务后更新我的tableView,我正在学习Swift,我不明白这段代码有什么问题。消息是一个字符串数组,我在每个json对象中附加一个message_body。我正在等待执行HTTP请求的任务来调用方法finishedLoading,我尝试在tableView中插入行。我收到此错误'Invalid update: invalid number of rows in section 0.'

感谢您的帮助

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
     cell.textLabel?.text = messages[indexPath.row]
     return cell
 }

func finishedLoading(array: Array<String>) {
    TableView.beginUpdates()
    TableView.insertRows(at: [IndexPath(row: messages.count-1, section: 0)], with: .automatic)
    TableView.endUpdates()
    TableView.reloadData()
}

public func init_chat()
{
        var request = URLRequest(url: URL(string: "URL")!)
        request.httpMethod = "GET"
        let session = URLSession.shared

        session.dataTask(with: request) {data, response, err in
            let json = try! JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
            let data = json?["data"] as? [[String: Any]]
            for message in data! {
                if let name = message["message_body"] as? String {
                    self.messages.append(name)
               }
           }
        self.finishedLoading(array: self.messages)
     }.resume()
}

2 个答案:

答案 0 :(得分:1)

你有几个问题。

  1. 您没有在主队列上重新加载表视图。
  2. 您正在后台队列中更新数据模型(messages)。
  3. 您要将新数据附加到主messages数组,但之后您只需添加一行就可以处理插入内容。
  4. 您致电insertRowsreloadData。只能打电话给其中一个。
  5. 您只需拨打一次beginUpdates/endUpdates即可使用insert/delete/reloadRowsAt
  6. 你有很多强行解缠。
  7. 要解决问题1,请将调用包裹在finishedLoading内的DispatchQueue.main.async

    DispatchQueue.main.async {
        self.finishedLoading(array: self.messages)
    }
    

    解决问题2和3更复杂。首先创建一个本地数组来收集新数据。然后将该数组传递给finishedLoading。然后更新finishedLoading以将新数组附加到messages并正确地通知表视图所有这些新行。

    以下是解决所有问题的更新代码。

    func finishedLoading(array: [String]) {
        let currentCount = messages.count
        messages.append(contentsOf: array)
        var newPaths = [IndexPath]()
        for row in 0..<array.count {
            newPaths.append(IndexPath(row: row+currentCount, section: 0))
        }
        TableView.insertRows(at: newPaths, with: .automatic)
    }
    
    public func init_chat()
    {
        var request = URLRequest(url: URL(string: "URL")!)
        request.httpMethod = "GET"
        let session = URLSession.shared
    
        session.dataTask(with: request) {data, response, err in
            if let data = data {
                let json = try! JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
                if let data = json?["data"] as? [[String: Any]] {
                    var newData = [String]()
                    for message in data {
                        if let name = message["message_body"] as? String {
                            newData.append(name)
                        }
                    }
                    if !newData.isEmpty() {
                        DispatchQueue.main.async {
                            self.finishedLoading(array: newData)
                        }
                    }
                }
            }
        }.resume()
    }
    

    我将其留作练习以摆脱try!的使用,并将其替换为正确的do/catch/try

    免责声明:上述代码尚未经过测试。可能存在拼写错误。

答案 1 :(得分:1)

添加此功能:

func numberOfRows(inSection section: Int) -> Int {
    return messages.count
}

并替换此代码:

self.finishedLoading(array: self.messages)

使用此代码:

DispatchQueue.main.async {
    self.tableView.reloadData()
}