Swift:当UITableView快速滚动时应用程序崩溃

3
我正在创建一个页面,用于在UITableView中从行业列表中选择用户所在的行业。这是一个配置档案过程的一部分。当用户选择行业时,它会被选中标记(如果之前没有选择),同时会被取消标记(如果之前已经选择)。
我已经编写了能够成功构建的代码,一切正常。但是,当我滚动得太快时,应用程序会崩溃,并显示以下错误:
2015-10-29 10:16:40.576 Protégé Version 1.0[10867:473794] * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 11 beyond bounds [0 .. 10]'
接下来是“First throw call stack”和所有文件的列表。奇怪的是,这似乎只发生在我滚动得太快时。而且通常突然间就会发生。
以下是我的代码。我已经搜索了与我得到的错误消息有关的任何内容,但在这种情况下似乎没有什么有用的东西。我无法找出问题在哪里,真的很感激任何帮助。我是Swift的新手,如果我的代码中有任何错误,请告诉我!先感谢大家:)
var array = ["Industry 1", "Industry 2", "Industry 3", "Industry 4", "Industry 5"]
var itemsSelected: [String] = []

override func viewDidLoad() {
    super.viewDidLoad()
}

确定有多少行

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

定义每个单元格的内容
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
    cell.textLabel?.text = array[indexPath.row]

    for var i = 0; i < selectedCells.count; i++ {
            let indexPath = NSIndexPath(forRow: selectedCells[i], inSection: 0)
            let checkedCell = tableView.cellForRowAtIndexPath(indexPath)
            checkedCell?.accessoryType = UITableViewCellAccessoryType.Checkmark
    }

    return cell
}

创建一个数组来存储所选单元格。
var selectedCells: [Int] = []

选择行 - 勾选和取消勾选

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
    let cell = tableView.cellForRowAtIndexPath(indexPath)

    // Checkmark & un-checkmark cell
    if cell!.accessoryType == UITableViewCellAccessoryType.None {
        cell!.accessoryType = UITableViewCellAccessoryType.Checkmark
    } else {
        cell!.accessoryType = UITableViewCellAccessoryType.None
    }

    // Add cell # to selectedCells array if it's a new selection. Remove if it's a deselection.
    if selectedCells.contains(indexPath.row) {
        selectedCells = selectedCells.filter {$0 != indexPath.row}
    } else {
        selectedCells.append(indexPath.row)
    }

    print(selectedCells)
}

将选定的字符串传输到主配置文件创建视图控制器。
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if segue.identifier == "selectionCompleted" {

        // Get the new view controller using segue.destinationViewController
        let destViewController: CreateProfileViewController = segue.destinationViewController as! CreateProfileViewController

        // Pass the selected object to the new view controller.
        destViewController.displayedSelection = array[0]
    }
}

提高返回主配置文件创建视图控制器的过渡速度

override func performSegueWithIdentifier(identifier: String, sender: AnyObject?) {

    if identifier == "selectionCompleted" {
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.performSegueWithIdentifier("selectionCompleted", sender: nil)
        })
    }
}

请问您能否在cellForRowAtIndexPath方法中打印indexPath.row并尝试快速滚动它吗? 这可能是由于您的indexPath.row值大于数组中的值所致。 - Karlos
我认为访问存储字符串的数组的indexPath.row并没有问题,因为单元格的数量似乎返回正确。 - MatthewLuiHK
1个回答

0

根据您提供的上下文,我猜测问题可能是由于您的“内容定义方法”和所选检查机制引起的。

我的猜测:

在您的tableView(:UITableView:NSIndexPath) -> UITableViewCell函数中,每次委托请求单元格时,它会遍历您的selectedArray。

由于NSArray(array)不是线程安全的,对selectedCell数组进行任何更改或快速访问都可能导致各种状态。当“快速滚动”会创建许多在同一时间访问相同数组的循环时,我认为这里可能会发生一些冲突。

让我给出一个建议。您可以使用Set代替数组。使用“包含”“插入”“删除”来控制状态,并且每个单元格仅管理自己。

也许像这样:

let cell = ...
...
if selectedSet.contains(indexPath.row){
    cell.accessoryType = UITableViewCellAccessoryType.Checkmark
}else{
    cell.accessoryType = UITableViewCellAccessoryType.None
}
...
return cell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接