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

BLE设备追踪App:AppDelegate调用ViewController刷新TableView无效问题

解决BLE设备追踪App中AppDelegate调用ViewController刷新无效的问题

我来帮你排查这个头疼的问题!这种情况十有八九是你在AppDelegate里调用的ViewController实例不是当前屏幕上正在显示的那个,所以刷新方法根本没作用到正确的界面上。下面是具体的分析和解决方案:

1. 先确认核心问题:实例不匹配

很多开发者会犯一个错误——直接在AppDelegate里new一个ViewController对象(比如let vc = ViewController()),但这个新创建的实例和导航栈里已经显示的VC完全是两个独立的对象,调用它的方法自然不会影响到实际界面。

你可以做个简单测试:

  • 在ViewController的viewDidLoad里加一句print("当前VC实例地址:", self)
  • 在AppDelegate里调用刷新方法前,也打印一下你拿到的VC实例地址
    对比两个地址,如果不一样,那就是实例不匹配的问题,接下来看正确的获取方式。

2. 正确的解决方案

方案一:获取当前显示的ViewController实例

通过AppDelegate获取窗口的根控制器,层层找到当前活跃的ViewController:

// 在AppDelegate中添加这个方法
private func getCurrentVisibleViewController() -> ViewController? {
    guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else {
        return nil
    }
    
    var currentVC = rootVC
    // 找到最上层的presented控制器
    while let presented = currentVC.presentedViewController {
        currentVC = presented
    }
    
    // 如果是导航控制器,取topViewController
    if let navVC = currentVC as? UINavigationController {
        return navVC.topViewController as? ViewController
    } else {
        return currentVC as? ViewController
    }
}

然后在蓝牙发现设备的回调里这样调用:

// 发现BLE设备后
if let targetVC = getCurrentVisibleViewController() {
    targetVC.refreshTableView()
}

方案二:用通知中心解耦(更推荐)

这种方式不需要AppDelegate直接持有ViewController的引用,代码解耦性更强,也避免了实例匹配的问题:

  1. 在ViewController里注册通知:
override func viewDidLoad() {
    super.viewDidLoad()
    // 注册刷新列表的通知
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(refreshTableView),
        name: NSNotification.Name(rawValue: "BLEDeviceListNeedsRefresh"),
        object: nil
    )
}

// 记得在销毁时移除通知,防止内存泄漏
deinit {
    NotificationCenter.default.removeObserver(self)
}
  1. 在AppDelegate的蓝牙回调里发送通知:
// 发现新设备后发送通知
NotificationCenter.default.post(
    name: NSNotification.Name(rawValue: "BLEDeviceListNeedsRefresh"),
    object: nil
)

3. 额外必查细节

  • 确保刷新操作在主线程执行:蓝牙回调通常在后台线程,而UI操作必须在主线程,所以你的refreshTableView方法要这么写:
@objc func refreshTableView() {
    DispatchQueue.main.async {
        self.tableView.reloadData()
    }
}
  • 检查数据源是否同步:如果AppDelegate更新了设备列表,但ViewController的数据源数组没有同步更新,就算调用reloadData也不会有变化。可以考虑把设备列表放在一个全局单例里,或者通过通知把新设备数据传递给ViewController。

内容的提问来源于stack exchange,提问作者Danf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:17:53