You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 02:06:01