简体   繁体   English

iOS和Swift:应用程序在UITableView向下滚动事件时崩溃

[英]iOS with Swift: App crashes on UITableView scroll down event

I am writing an iOS app in Swift that puts data from an API into a TableView. 我正在用Swift编写一个iOS应用,该应用将来自API的数据放入TableView中。 The goal is that the user can scroll down a continuous list of blog posts. 目标是用户可以向下滚动博客帖子的连续列表。 What is happening is that data is filling the first screen's amount of cells fine, but when the user scrolls down, the app crashes as one of the cell properties, cellImageView becomes nil and is unwrapped (as force unwrap is specified in the cell class's code): 发生的情况是,数据可以很好地填充第一个屏幕的单元格数量,但是当用户向下滚动时,应用程序由于单元格属性之一而崩溃, cellImageView变为nil并且被解包(因为在单元格类的代码中指定了强制解包) ):

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

Here is the code that causes the crash: 这是导致崩溃的代码:

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
}

The interesting thing is that if do this: 有趣的是,如果这样做:

    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)

, the app doesn't crash but the data just repeats over and over again as the user scrolls. ,应用程序不会崩溃,但数据会随着用户滚动而重复一遍又一遍。

I've tried the solution to a similar problem here: Why does data returned from coredata become nil after tableview scroll in swift? 我在这里尝试过解决类似问题的解决方案: 为什么在快速滚动tableview之后,从coredata返回的数据为何变为nil? , but that did not work. ,但这没有用。 However, I do believe this has to do with the asynchronous API calls. 但是,我确实认为这与异步API调用有关。

I am thinking that possible solutions may include population an array of API data before generating the cells, but I would like some insight on the source of this problem before a rethink the architecture of the code. 我认为可能的解决方案可能包括在生成单元之前填充一组API数据,但是在重新考虑代码的体系结构之前,我希望对此问题的来源有所了解。

You need to make an API call in your viewDidLoad to know how many element are there and record their ID in an array. 您需要在viewDidLoad进行API调用,以了解其中有多少个元素并将其ID记录在数组中。 Then in your cellForRow function, you can get the id in this way 然后在您的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
}

The reason your nextCell wont work is that, this cellForRow function is called every time when your table view is trying to display a cell that is not currently on your screen. 您的nextCell无法工作的原因是,每次当表视图试图显示当前不在屏幕上的单元格时,都会调用此cellForRow函数。 Say you know you have 10 element and your screen can only display 5 of them. 假设您知道您有10个元素,并且屏幕上只能显示5个元素。 When you scroll to bottom, your nextCell will become 10 and everything works fine as now. 当您滚动到底部时,您的nextCell将变为10,并且一切正常。 But now when you scroll up, the table view have to prepare the previous 5 again. 但是现在当您向上滚动时,表格视图必须再次准备前5个。 So now your nextCell becomes 15, which you don't have corresponding element in your API call. 因此,现在您的nextCell变为15,您在API调用中没有相应的元素。

It is bad practice to call any API in cellForRowAt indexPath: IndexPath, it produces crashes as you see, have a look at MVVM. 不好的做法是在cellForRowAt indexPath:IndexPath中调用任何API,如您所见,它会导致崩溃,请看一下MVVM。 It is like wining a war without having to go to battle and I refer to this instance where you call API in cellForRowAt indexPath: IndexPath and the outlets are not initialised. 这就像赢得一场战争而不必参加战斗一样,我指的是您在cellForRowAt indexPath中调用API的此实例:IndexPath并且出口未初始化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM