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

iOS 26中UITableView与UICollectionView无法随@Observable数据源自动刷新的问题排查

iOS 26中UITableView与UICollectionView无法随@Observable数据源自动刷新的问题排查

嗨,我来帮你捋清楚这个自动刷新失效的问题,其实核心是没搞懂iOS 17+引入的@Observable在UIKit中的正确用法,咱们一步步拆解:

一、先看你的UITableView案例问题

你当前的代码里,words数组是WordTableViewController的普通属性,虽然单个Word类加了@Observable,但系统没法感知到数组的添加/删除/替换操作——因为@Observable要作用在「持有数据源的容器对象」上,而不是单个数据模型。

修正方案:把数据源封装成Observable容器

咱们创建一个专门的WordStore类来持有words数组,并给它加上@Observable,这样数组的任何变化都会被系统检测到,自动触发UITableView刷新:

@Observable @MainActor class WordStore {
    // 把数组放到Observable容器里
    var words = [Word(value: "First"), Word(value: "Second"), Word(value: "Third")]
}

@Observable @MainActor class Word {
    var value: String
    init(value: String) {
        self.value = value
    }
}

class WordTableViewController: UITableViewController {
    // 持有Observable数据源容器
    let wordStore = WordStore()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        navigationItem.rightBarButtonItem = UIBarButtonItem(
            title: "Refresh",
            style: .plain,
            target: self,
            action: #selector(refreshWords)
        )
    }
    
    @objc private func refreshWords() {
        // 修改Observable容器里的数组
        wordStore.words.append(Word(value: "John Doe"))
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        wordStore.words.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        var content = cell.defaultContentConfiguration()
        content.text = wordStore.words[indexPath.row].value
        cell.contentConfiguration = content
        return cell
    }
}

二、再看你的UICollectionView案例问题

你这里虽然把customers数组放到了@Observable的CustomerStore里,但有两个小问题:

  1. configurationUpdateHandler是用来响应cell状态变化(比如选中、高亮)的,不会在数据源变化时自动触发;
  2. 虽然Customer是@Observable,但修改单个对象的属性后,系统没法自动通知UICollectionView更新对应cell。

修正方案:配合DiffableDataSource使用(推荐)

UICollectionViewDiffableDataSource能高效处理数据变化,和@Observable搭配使用体验最好,修改后的代码如下:

@Observable class CustomerStore {
    var customers = [Customer(name: "John Doe"), Customer(name: "Mary Doe")]
}

@Observable class Customer {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class CustomerCollectionViewController: UICollectionViewController {
    let store = CustomerStore()
    // 声明Diffable数据源
    private var dataSource: UICollectionViewDiffableDataSource<Int, Customer>?
    
    init() {
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: UIScreen.main.bounds.width - 32, height: 60)
        layout.sectionInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
        layout.minimumLineSpacing = 12
        super.init(collectionViewLayout: layout)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
        self.title = "Customers"
        self.navigationController?.navigationBar.prefersLargeTitles = true
        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Update", style: .plain, target: self, action: #selector(updateCustomer))
        
        // 初始化Diffable数据源
        setupDataSource()
        // 加载初始数据
        applySnapshot()
    }
    
    private func setupDataSource() {
        dataSource = UICollectionViewDiffableDataSource<Int, Customer>(collectionView: collectionView) { collectionView, indexPath, customer in
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath)
            var content = UIListContentConfiguration.cell()
            content.text = customer.name
            cell.contentConfiguration = content
            return cell
        }
    }
    
    private func applySnapshot() {
        var snapshot = NSDiffableDataSourceSnapshot<Int, Customer>()
        snapshot.appendSections([0])
        snapshot.appendItems(store.customers)
        // 应用快照,自动更新UI
        dataSource?.apply(snapshot, animatingDifferences: true)
    }
    
    @objc private func updateCustomer() {
        store.customers[0].name = "Steven Smith"
        // 数据源变化后重新应用快照
        applySnapshot()
        print(store.customers)
    }
}

核心总结

  • @Observable要作用在持有列表/数组的容器类上,而不是单个数据模型(模型加@Observable是为了感知单个属性变化,但容器才是让系统感知列表变化的关键);
  • UIKit中的表格/集合视图,推荐配合DiffableDataSource使用@Observable,既能自动感知数据变化,又能高效更新UI;
  • 如果不想用DiffableDataSource,也可以在Observable数据源变化时手动调用tableView.reloadData()或collectionView.reloadData(),但效率不如前者。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 11:04:33