【问题标题】:Deleting of rows in UITableView takes too much time删除 UITableView 中的行需要太多时间
【发布时间】:2017-05-17 14:17:22
【问题描述】:

我正在编写一个程序,它有 40k (40000) 个项目的数组,并在 UITableView 中显示它,搜索表应该过滤后只显示搜索结果。

问题是一次删除多行(例如 30000+)大约需要 10 - 20 秒,并且肯定无法使用。你能建议这个问题的任何决定吗?

tableview.reloadData() 不适合)

var allProducts = [Product]()
@IBOutlet weak var searchTableView: UITableView!
@IBOutlet weak var searchTextField: UITextField?

var searchResults = [Product]()

enum Action{
    case Insert
    case Ignore
    case Remove
}

override func viewDidLoad() {
    super.viewDidLoad()
    searchTextField?.addTarget(self, action: #selector(ViewController.textFieldDidChanged(_:)), for: .editingChanged)
    DBBrain().getAllAlcProducts() { [weak self] products in
        self?.allProducts = products
    }
}

func textFieldDidChanged(_ sender: UITextField){
    DispatchQueue.global(qos: .userInitiated).async { [weak self] in
        let text = sender.text!.lowercased()
        let res = self!.allProducts.filter({ $0.name.lowercased().contains(text) })
        if self?.searchTextField?.text != nil && text == self!.searchTextField!.text!{
            if let values = self?.getIndexes(forResults: res){
                self?.searchResults = res
                self?.updateTable(action: values.0, indexes: values.1)
            }
        }
    }
}

private func getIndexes(forResults products: [Product]) -> (Action, [IndexPath]){
    var indexes = [IndexPath]()
    var action = Action.Ignore
    if searchResults.count > products.count{
        var newCounter = 0
        for x in 0..<searchResults.count {
            if products.isEmpty || searchResults[x].id != products[newCounter].id {
                indexes.append(IndexPath(row: x, section: 0))
            }else {
                if newCounter < products.count - 1{
                    newCounter += 1
                }
            }
        }
        action = Action.Remove
    }else if searchResults.count < products.count{
        var oldCounter = 0
        for x in 0..<products.count {
            if searchResults.isEmpty || searchResults[oldCounter].id != products[x].id {
                indexes.append(IndexPath(row: x, section: 0))
            }else {
                if oldCounter < searchResults.count - 1 {
                    oldCounter += 1
                }
            }
        }
        action = Action.Insert
    }
    return (action, indexes)
}

private func updateTable(action: Action, indexes: [IndexPath]) {
    DispatchQueue.main.async { [weak self] in
        if action != .Ignore {
            if action == .Remove {
                self?.searchTableView.beginUpdates()
                self?.searchTableView.deleteRows(at: indexes, with: .fade)
                self?.searchTableView.endUpdates()
            }else if action == .Insert {
                self?.searchTableView.beginUpdates()
                self?.searchTableView.insertRows(at: indexes, with: .fade)
                self?.searchTableView.endUpdates()
            }
        }
    }
}


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

【问题讨论】:

  • 您的应用会在这 10-20 秒内冻结吗?如果是这样,您应该确保删除是异步执行的。
  • 为什么要一次删除 30000 行?您需要使用有关您正在做什么的更多相关信息来更新您的问题。
  • 也许您可以阅读“无限列表”技术。它可能会让您了解如何为 UITableView(或任何列表)处理大量元素。只考虑屏幕内的内容以及更改后屏幕内的内容。
  • 在 tableView 中向用户展示 40000 个项目是个坏主意。即使删除了 30000 多个项目,也没有用户愿意滚动浏览剩余的 10000 个项目。认真考虑重构您的数据模型并以更结构化的方式呈现数据,这种方式是有用和可用的。
  • @Matt Le Fleur 是的,天气很冷。列表(数据源)的排序需要不到 1 秒的时间并且是异步的,但是 UI 的准确更新需要所有时间,我无法在后台执行它

标签: ios swift uitableview


【解决方案1】:

您永远不应该有一个包含 30k+ 单元格的表格。这是对内存的荒谬使用。您应该为 rowsForSection 委托方法中的单元格数设置最大限制。

获取结果的计数,如果计数大于 30 左右(即使是一个很大的数字),请将其设置为 30。

它也很可能拥有一个超级庞大的数组。这会占用大量内存,即使您没有为它们制作单元格。

【讨论】:

  • 是的,谢谢你和所有其他人,我想我会尝试重新设计算法以呈现更少的单元格,并将其发布在这里.. 可能对任何人都有用)
猜你喜欢
  • 2018-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-06
  • 1970-01-01
  • 2017-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多