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里,但有两个小问题:
configurationUpdateHandler是用来响应cell状态变化(比如选中、高亮)的,不会在数据源变化时自动触发;- 虽然
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
相关产品推荐
相关产品推荐

