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

如何获取UICollectionView已注册补充视图类型?无需额外类的查询方法

关于UICollectionView已注册补充视图类型的查询方案

嘿,这个问题问到点子上了!很多开发者都会遇到类似的需求,我来给你详细说说:

核心结论:没有官方公开API直接查询

UICollectionView本身并没有提供公开的官方方法来直接获取已注册的补充视图类型——苹果把这些注册信息封装在了内部私有结构里,不会暴露给开发者。所以你想要的那种直接调用collectionView.supKinds()的原生方法是不存在的,除非你用私有API,但那会导致App审核不通过,还可能因为系统版本更新而失效,绝对不推荐在生产环境使用。

无需子类化的可行方案:关联对象+扩展

如果你不想子类化UICollectionView,我们可以用Objective-C关联对象给UICollectionView添加一个扩展,在每次注册补充视图时同步记录这些类型。这样既能保持原有代码结构,又能实现查询功能:

代码实现

import ObjectiveC
import UIKit

// 定义关联对象的唯一key
private var registeredSupplementaryViewsKey = 0

extension UICollectionView {
    /// 获取所有已注册的补充视图类型,按elementKind分组
    func registeredSupplementaryViewTypes() -> [String: [AnyClass]] {
        return objc_getAssociatedObject(self, &registeredSupplementaryViewsKey) as? [String: [AnyClass]] ?? [:]
    }
    
    /// 包装系统注册方法,同步记录视图类型(纯代码注册)
    func registerSupplementaryView<T: UICollectionReusableView>(_ viewClass: T.Type, forSupplementaryViewOfKind elementKind: String) {
        // 先执行系统原生注册逻辑
        register(viewClass, forSupplementaryViewOfKind: elementKind, withReuseIdentifier: String(describing: viewClass))
        
        // 记录当前注册的类型
        updateRegisteredSupplementaryViews(for: elementKind, adding: viewClass)
    }
    
    /// 包装系统注册方法,同步记录视图类型(Nib注册)
    func registerNibForSupplementaryView<T: UICollectionReusableView>(_ nib: UINib, viewClass: T.Type, forSupplementaryViewOfKind elementKind: String) {
        register(nib, forSupplementaryViewOfKind: elementKind, withReuseIdentifier: String(describing: viewClass))
        
        // 记录当前注册的类型
        updateRegisteredSupplementaryViews(for: elementKind, adding: viewClass)
    }
    
    // 私有辅助方法:更新注册记录
    private func updateRegisteredSupplementaryViews(for elementKind: String, adding viewClass: AnyClass) {
        var registeredViews = registeredSupplementaryViewTypes()
        if var types = registeredViews[elementKind] {
            // 避免重复记录同一类型
            guard !types.contains(viewClass) else { return }
            types.append(viewClass)
            registeredViews[elementKind] = types
        } else {
            registeredViews[elementKind] = [viewClass]
        }
        // 保存到关联对象
        objc_setAssociatedObject(self, &registeredSupplementaryViewsKey, registeredViews, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

使用方式

  1. 以后注册补充视图时,使用扩展里的registerSupplementaryView(_:forSupplementaryViewOfKind:)或registerNibForSupplementaryView(_:viewClass:forSupplementaryViewOfKind:)方法,替代系统原生的注册方法。
  2. 当你需要查询已注册类型时,直接调用:
    let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
    // 注册补充视图
    collectionView.registerSupplementaryView(MyHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader)
    // 查询所有已注册类型
    let registeredTypes = collectionView.registeredSupplementaryViewTypes()
    // 比如获取所有Header类型
    let headerTypes = registeredTypes[UICollectionView.elementKindSectionHeader]
    

备选方案:子类化UICollectionView

如果你愿意子类化,也可以创建自定义的MyChildUICollectionView,重写所有注册补充视图的方法,在内部维护一个字典来记录注册类型。不过这种方式需要你在项目中统一使用子类,灵活性不如关联对象的方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:48:16