UITableView 上的用户交互会阻塞进程

User interaction on UITableView blocks processes

我有一个 TabelViewController。 TableViewCells 中的数据通过 tableview.reloadData() 以高频率(假设为 10 Hz)更新。到目前为止这有效。但是当我滚动 TableView 时,更新会暂停,直到用户交互结束。我的应用程序中的所有其他进程也已暂停。我该如何解决这个问题?

这是一个 TableViewController 示例。如果您 运行 在您的模拟器上执行此操作并检查调试区域内的输出,您会注意到,当您滚动并按住表视图。如果你在另一个 class.

中有进程,也是如此

有趣的是,如果您与 MapView 交互,则不会出现这种进程阻塞。我在这里错过了什么?

import UIKit

class TableViewController: UITableViewController {
    
    var text = 0
    var timer = Timer()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        NotificationCenter.default.addObserver(self, selector: #selector(self.recieveNotification), name: NSNotification.Name(rawValue: "testNotificatiion"), object: nil)
        
        scheduledTimerWithTimeInterval()
    }
    
    func scheduledTimerWithTimeInterval(){
        timer = Timer.scheduledTimer(timeInterval: 1/10, target: self, selector: #selector(self.updateCounting), userInfo: nil, repeats: true)
    }
    
    @objc func updateCounting(){
        text += 1
        
        let userInfo = ["test": text]
        
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "testNotificatiion"), object: nil, userInfo: userInfo)
        
        tableView.reloadData()
    }
    
    @objc func recieveNotification(notification: Notification){
        
        if let userInfo = notification.userInfo! as? [String: Int]
        {
            if let recieved = userInfo["test"] {
                print("Notification recieved with userInfo: \(recieved)")
            }
        }
    }
    
    // MARK: - Table view data source
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell: UITableViewCell?
        cell = tableView.dequeueReusableCell(withIdentifier: "rightDetail", for: indexPath)
        cell?.detailTextLabel?.text = String(text)

        return cell!
    }
}

计时器不会在 UITableView 滚动时触发。查看 Quinn The Eskimo 的回答 here

将你的方法改成这样,即使在滚动时它也会起作用。

func scheduleMyTimer() {
    let t = Timer(timeInterval: 1.0, repeats: true) { _ in
        self.updateCounting()
    }
    RunLoop.current.add(t, forMode: RunLoop.Mode.common)
}

CoreLocation 回调在滚动 UITableView 时也不会触发。这是一个解决方法。

来自 CLLocationManagerDelegate 的文档:

Core Location calls the methods of your delegate object on the runloop from the thread on which you initialized CLLocationManager. That thread must itself have an active run loop, like the one found in your app’s main thread.

所以我改变了 CLLocationManager 初始化:

class AppDelegate {
    var lm = CLLocationManager()
}

为此:

class AppDelegate {
    var lm: CLLocationManager!
    var thread: Thread!

    func didFinishLaunching() {
        thread = Thread {
            self.lm = CLLocationManager()

            Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (_) in
                // empty on purpose
            }
        
            RunLoop.current.run()

            // If no input sources or timers are attached
            // to the run loop, the run() method exits immediately,
            // so we add a Timer just before the call.

        }
        thread.start()
    }
}

然后即使在滚动时委托回调也会继续触发。 回答有帮助。