带Swift的iOS:App在UITableView向下滚动事件时崩溃

时间:2017-06-18 03:04:44

标签: ios iphone swift uitableview asynchronous

我正在Swift中编写一个iOS应用程序,它将来自API的数据放入TableView。目标是用户可以向下滚动连续的博客帖子列表。发生的事情是数据正在填充第一个屏幕的单元格数量,但当用户向下滚动时,应用程序崩溃为单元格属性之一,cellImageView变为nil并且unwrapped(在单元类的代码中指定强制解包):

class BlogPostEntryCell: UITableViewCell {
    //MARK: Properites
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var bodyTextView: UITextView!
    @IBOutlet weak var initialsImageView: UIImageView!   
}

以下是导致崩溃的代码:

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

    apiCaller.getAPIDataThroughAsyncCall(id: nextCell, entry: { cellContent in
        DispatchQueue.main.async(execute: {
            cell.cellLabel.text = cellContent.labelText
            cell.cellTextView.text = cellContent.textViewText
            // App crashes at the below line
            cell.initialsImageView = self.createPicture(initials: cellContent.pictureText)
        })
    })

    nextCell += 1

    return cell
}

有趣的是,如果这样做:

    cell.cellLabel?.text = cellContent.labelText
    cell.cellTextView?.text = cellContent.textViewText
    // App does NOT crash at the below line
    cell.initialsImageView? = self.createPicture(initials: cellContent.pictureText)

,应用程序没有崩溃,但数据只是在用户滚动时反复重复。

我在这里尝试了类似问题的解决方案:Why does data returned from coredata become nil after tableview scroll in swift?,但这不起作用。但是,我确实认为这与异步API调用有关。

我认为可能的解决方案可能包括在生成单元格之前填充一系列API数据,但在重新考虑代码体系结构之前,我想了解一下这个问题的来源。

2 个答案:

答案 0 :(得分:2)

您需要在viewDidLoad中进行API调用,以了解其中有多少元素并将其ID记录在数组中。然后在cellForRow函数中,您可以通过这种方式获取ID

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

    apiCaller.getAPIDataThroughAsyncCall(id: array[indexPath.row], entry: { cellContent in
        DispatchQueue.main.async(execute: {
            ...
        })
    })
    return cell
}

你的nextCell无法工作的原因是,每当你的表视图试图显示当前不在屏幕上的单元格时,就会调用此cellForRow函数。假设你知道你有10个元素,你的屏幕只能显示5个元素。当你滚动到底部时,你的nextCell将变为10,一切正常,就像现在一样。但是现在当你向上滚动时,表视图必须再次准备前5个。所以现在你的nextCell变为15,你在API调用中没有相应的元素。

答案 1 :(得分:0)

在cellForRowAt indexPath中调用任何API是不好的做法:IndexPath,如你所见,它会产生崩溃,看看MVVM。这就像赢得战争而不必参加战斗一样,我指的是你在cellForRowAt indexPath中调用API的实例:IndexPath并且没有初始化插座。