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

UICollectionView中输入时UISearchBar频繁失去第一响应者问题

问题解决:UICollectionView头部搜索栏失焦与快照应用崩溃

问题根源

  1. 搜索栏失焦:每次更新filteredWords触发dataSource.apply(snapshot)时,UICollectionView会重新生成头部补充视图,原搜索栏被销毁或复用,导致失去第一响应者状态。
  2. 队列崩溃:移除DispatchQueue.main.async后,filteredWords的设置可能在非主队列执行,而UICollectionViewDiffableDataSource要求必须在主队列应用快照,因此触发崩溃。

修复方案

核心思路

确保快照始终在主队列应用,同时保留搜索栏的引用,避免视图复用导致焦点丢失。

1. 在ViewController中添加搜索栏引用

class ViewController: UIViewController {
    let words = ["foo", "bar"]
    var filteredWords = ["foo", "bar"] {
        didSet {
            DispatchQueue.main.async { [weak self] in
                guard let self else { return }
                self.dataSource.apply(self.snapshot, animatingDifferences: false)
                // 恢复搜索栏焦点
                self.searchBar?.becomeFirstResponder()
            }
        }
    }
    
    var collectionView: UICollectionView!
    var dataSource: UICollectionViewDiffableDataSource<String, String>!
    private var searchBar: UISearchBar? // 新增搜索栏引用
    // ... 原有代码
}

2. 修改头部注册逻辑,保存搜索栏引用

func configureDataSource() {
    // ... 原有代码
    let searchbarHeaderRegistration = UICollectionView.SupplementaryRegistration<SearchBarCell>(elementKind: UICollectionView.elementKindSectionHeader) { [weak self] cell, _, _ in
        self?.searchBar = cell.searchBar
        cell.searchBar.delegate = self
    }
    // ... 原有代码
}

3. 移除delegate方法中的冗余异步包裹

extension ViewController: UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        filteredWords = words.filter { $0.hasPrefix(searchText) }
    }
    
    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        filteredWords = words
    }
}

额外优化建议

  • 始终使用animatingDifferences: false更新快照,减少视图复用频率,降低焦点丢失概率。
  • 如果需要保留动画效果,可以在更新快照前记录搜索栏的当前文本和焦点状态,更新后恢复。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 07:45:36