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

Mac端iPad适配App中UICollectionViewCell内嵌UITextView致CPU飙升

UICollectionView内嵌UITextView在Mac适配模式下滚动CPU飙升问题

问题描述

我开发了一个简单的UIKit应用,在UICollectionViewCell中内嵌了UITextView,该应用在iOS/iPadOS平台运行正常,但在Mac(iPad适配模式)下,滚动UICollectionView时CPU占用率会飙升至约85%并持续居高不下,仅当点击应用窗口外部切换到后台时CPU占用才会下降,切回前台后又立刻回升。我也尝试了Catalyst模式,同样存在该问题,只是CPU占用率略低(约45%)。

此外,滚动时调试器持续输出日志:[API] cannot add handler to 3 from 3 - dropping

请问有人能解释该问题或提供解决方案吗?

环境信息

  • Xcode Version 14.1 (14B47b)
  • macOS Ventura 13.0 (22A380)

代码示例

ViewController代码

class ViewController: UIViewController {
    var dataSource: UICollectionViewDiffableDataSource<Section, String>! = nil
    var collectionView: UICollectionView! = nil
    var items = Array(0...100).map{"Item \($0)"}
    
    enum Section: String {
        case main
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.title = "List"
        configureCollectionView()
        configureDataSource()
        applyInitialSnapshot()
    }
    
    private func createLayout() -> UICollectionViewLayout {
        return UICollectionViewCompositionalLayout { sectionIndex, layoutEnvironment in
            let size = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(100))
            let item = NSCollectionLayoutItem(layoutSize: size)
            let group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitems: [item])
            
            return NSCollectionLayoutSection(group: group)
        }
    }
    
    private func configureCollectionView() {
        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        collectionView.backgroundColor = .systemBackground
        view.addSubview(collectionView)
    }
    
    private func configureDataSource() {
        let cellRegistration = UICollectionView.CellRegistration<TestCell, String> { (cell, indexPath, item) in
            cell.configure(title: item, row: indexPath.item)
        }
        
        dataSource = UICollectionViewDiffableDataSource<Section, String>(collectionView: collectionView) {
            (collectionView, indexPath, identifier) -> UICollectionViewCell? in
            
            return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)
        }
    }
    
    private func applyInitialSnapshot() {
        var snapshot = NSDiffableDataSourceSnapshot<Section, String>()
        snapshot.appendSections([.main])
        snapshot.appendItems(items)
        
        dataSource.apply(snapshot, animatingDifferences: false)
    }
}

TestCell代码

class TestCell: UICollectionViewCell {
    private let annotationsTextView = UITextView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        addViews()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func configure(title: String, row: Int) {
        annotationsTextView.attributedText = .init(string: "Row: \(row) Item: \(title)", attributes: [.font: UIFont.preferredFont(forTextStyle: .title1)])
    }
    
    private func addViews() {
        annotationsTextView.isScrollEnabled = false
        annotationsTextView.isEditable = false
        annotationsTextView.translatesAutoresizingMaskIntoConstraints = false
        
        contentView.addSubview(annotationsTextView)
        
        NSLayoutConstraint.activate([
            annotationsTextView.topAnchor.constraint(equalTo: contentView.topAnchor),
            annotationsTextView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            annotationsTextView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            annotationsTextView.trailingAnchor.constraint(equalTo:  contentView.trailingAnchor),
        ])
    }
}

问题原因与解决方案

问题原因

这个问题源于UITextView在Mac的iPad适配/Catalyst模式下的底层交互逻辑冗余:即使禁用了滚动和编辑功能,UITextView仍会保留文本选择、富文本编辑等相关的后台处理逻辑,当CollectionView滚动复用单元格时,这些逻辑会被频繁触发,导致大量不必要的计算,进而引发CPU占用飙升。调试日志[API] cannot add handler to 3 from 3 - dropping也反映了UITextView在Mac平台上的交互处理存在内部冲突。

解决方案

方案1:替换UITextView为UILabel(推荐)

由于你的场景仅需展示文本,无需编辑或滚动功能,UILabel是更轻量、性能更稳定的替代方案,完全支持富文本展示。修改后的TestCell代码如下:

class TestCell: UICollectionViewCell {
    private let annotationsLabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        addViews()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func configure(title: String, row: Int) {
        annotationsLabel.attributedText = .init(string: "Row: \(row) Item: \(title)", attributes: [.font: UIFont.preferredFont(forTextStyle: .title1)])
    }
    
    private func addViews() {
        annotationsLabel.numberOfLines = 0 // 支持多行文本换行
        annotationsLabel.translatesAutoresizingMaskIntoConstraints = false
        
        contentView.addSubview(annotationsLabel)
        
        NSLayoutConstraint.activate([
            annotationsLabel.topAnchor.constraint(equalTo: contentView.topAnchor),
            annotationsLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            annotationsLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            annotationsLabel.trailingAnchor.constraint(equalTo:  contentView.trailingAnchor),
        ])
    }
}

方案2:优化UITextView配置(需保留UITextView时使用)

若因业务需求必须使用UITextView,可通过禁用更多不必要的交互功能来降低CPU占用:

private func addViews() {
    annotationsTextView.isScrollEnabled = false
    annotationsTextView.isEditable = false
    annotationsTextView.isSelectable = false // 禁用文本选择
    annotationsTextView.allowsEditingTextAttributes = false // 禁用富文本编辑
    annotationsTextView.textContainerInset = .zero // 重置内边距,减少布局计算
    annotationsTextView.textContainer.lineFragmentPadding = 0 // 重置行内边距
    annotationsTextView.translatesAutoresizingMaskIntoConstraints = false
    
    contentView.addSubview(annotationsTextView)
    
    NSLayoutConstraint.activate([
        annotationsTextView.topAnchor.constraint(equalTo: contentView.topAnchor),
        annotationsTextView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
        annotationsTextView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
        annotationsTextView.trailingAnchor.constraint(equalTo:  contentView.trailingAnchor),
    ])
}

这些设置能减少UITextView的后台计算量,一定程度缓解CPU占用问题,但效果不如替换为UILabel显著。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 11:25:32