iOS开发UITableView.reloadData()需仅在主线程调用报错如何修复?
报错产生原因
- UIKit框架有强制规则:所有UI相关的操作、UI属性的读写必须在主线程执行,在子线程操作UI元素会直接触发运行时检查报错。
- 你代码的问题出在
NotificationCenter的观察者回调逻辑:调用addObserver方法时传入的queue参数为nil,系统会默认在发送通知的线程执行回调闭包。如果你的dataRefreshed通知是在子线程中发送的,那么回调内的tableView.reloadData()调用、tableView属性访问、navigationItem.title赋值三个UI相关操作都会在子线程执行,刚好触发你遇到的两个主线程报错。
修复方案
提供两种可行的修复方式,根据你的业务场景选择即可:
方案1:指定通知回调执行队列为主队列
修改addObserver的queue参数,直接传入主队列OperationQueue.main,后续不管通知在哪个线程发送,回调都会自动切到主线程执行,无需额外处理:
import UIKit class CoursesController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() // 仅修改queue参数为.main即可 NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "dataRefreshed") , object: nil, queue: .main) { (notification) in self.tableView.reloadData() self.navigationItem.title = Model.shared.currentDate } navigationItem.title = Model.shared.currentDate } }
方案2:回调内部手动将UI操作分发到主线程
如果回调内有非UI的耗时处理逻辑需要在子线程执行,可以在UI操作的位置用GCD手动切换到主线程:
import UIKit class CoursesController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "dataRefreshed") , object: nil, queue: nil) { (notification) in // 此处可放子线程执行的非UI耗时逻辑 // UI操作统一包在主线程执行 DispatchQueue.main.async { self.tableView.reloadData() self.navigationItem.title = Model.shared.currentDate } } navigationItem.title = Model.shared.currentDate } }
- 补充注意:使用
NotificationCenter添加观察者后,需要在页面销毁时调用NotificationCenter.default.removeObserver(self)移除观察者,避免出现野指针崩溃。
内容的提问来源于stack exchange,提问作者Anonymous
相关产品推荐
相关产品推荐

