Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView all registered classes / nibs

How can I view already registered classes and/or nibs and their cell identifier?

I would like to see which have been automatically registered within the xib (if that's how it's done), but also being able to see any manually registered would be great too.

like image 802
Michael Ozeryansky Avatar asked Jul 22 '15 23:07

Michael Ozeryansky


4 Answers

Swift

let registeredCellClasses = tableView.value(forKey: "_cellClassDict") as? [String:Any]
let registeredNibs = tableView.value(forKey: "_nibMap") as? [String:UINib]
like image 159
Peter Kreinz Avatar answered Nov 09 '22 04:11

Peter Kreinz


Details

  • Xcode 12.3 (12C33)
  • Swift 5.3

Problem

Usage of the _nibMap and _cellClassDict may be not safe. Apple has not direct API to get registered cells. So, solutions based on _nibMap and _cellClassDict looks like hacks. And we can not predict, will Apple change this API or not. I suggest to make own TableView and implement storing logic there.

Solution

class TableView: UITableView {
    private (set) lazy var registeredCellIdentifiers = Set<String>()
    
    func register(nib: UINib?, forCellReuseIdentifier identifier: String) {
        super.register(nib, forCellReuseIdentifier: identifier)
        registeredCellIdentifiers.insert(identifier)
    }
    
    func register(nib: UINib?, forHeaderFooterViewReuseIdentifier identifier: String) {
        super.register(nib, forHeaderFooterViewReuseIdentifier: identifier)
        registeredCellIdentifiers.insert(identifier)
    }
    
    func register(cellClass: AnyClass?, forCellReuseIdentifier identifier: String) {
        super.register(cellClass, forCellReuseIdentifier: identifier)
        registeredCellIdentifiers.insert(identifier)
    }
    
    func register(aClass: AnyClass?, forHeaderFooterViewReuseIdentifier identifier: String) {
        super.register(aClass, forHeaderFooterViewReuseIdentifier: identifier)
        registeredCellIdentifiers.insert(identifier)
    }

    @available(*, deprecated, message: "use register(nib: UINib?, forCellReuseIdentifier identifier: String) instead")
    override func register(_ nib: UINib?, forCellReuseIdentifier identifier: String) {}
    
    @available(*, deprecated, message: "use register(nib: UINib?, forCellReuseIdentifier identifier: String) instead")
    override func register(_ nib: UINib?, forCellReuseIdentifier identifier: String) {}
    
    @available(*, deprecated, message: "use register(nib: UINib?, forHeaderFooterViewReuseIdentifier identifier: String) instead")
    override func register(_ nib: UINib?, forHeaderFooterViewReuseIdentifier identifier: String) { }

    @available(*, deprecated, message: "ude register(cellClass: AnyClass?, forCellReuseIdentifier identifier: String) instead")
    override func register(_ cellClass: AnyClass?, forCellReuseIdentifier identifier: String) {}

    @available(*, deprecated, message: "use register(aClass: AnyClass?, forHeaderFooterViewReuseIdentifier identifier: String) instead")
    override func register(_ aClass: AnyClass?, forHeaderFooterViewReuseIdentifier identifier: String) {}
}

Full Sample

Do not forget to paste here code defined above

// MARK: - Auto Generated identifiers

protocol Identifiable: class {
    static var identifier: String { get }
}

extension Identifiable {
    static var identifier: String { "\(self)" }
}

// MARK: - Define Cells

class TableViewCell: UITableViewCell, Identifiable {
    var mainBackgroundColor: UIColor { .white }
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        backgroundColor = mainBackgroundColor
    }

    @available(*, deprecated, message: "")
    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}

class GreenCell: TableViewCell {
    override var mainBackgroundColor: UIColor { .green }
}

class OrangeCell: TableViewCell {
    override var mainBackgroundColor: UIColor { .orange }
}

// MARK: ViewController

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        let tableView = TableView()
        view.addSubview(tableView)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        
        tableView.register(cellClass: GreenCell.self, forCellReuseIdentifier: GreenCell.identifier)
        tableView.register(cellClass: OrangeCell.self, forCellReuseIdentifier: OrangeCell.identifier)
        tableView.dataSource = self
        
        print(tableView.registeredCellIdentifiers)
    }
}

// MARK: - UITableViewDataSource

extension ViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int { 1 }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 10 }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let identifier = (indexPath.row % 2) == 0 ? GreenCell.identifier :  OrangeCell.identifier
        return tableView.dequeueReusableCell(withIdentifier: identifier) ?? UITableViewCell()
    }
}
like image 35
Vasily Bodnarchuk Avatar answered Nov 09 '22 04:11

Vasily Bodnarchuk


UITableView stores information about registered cell classes and nibs in separate dictionaries, which you can get using KVC and private property keys:

NSDictionary *registeredCellClasses = [tableView valueForKey:@"_cellClassDict"];
NSDictionary *registeredNibs = [tableView valueForKey:@"_nibMap"];

Each dictionary stores registered cell reuse identifiers as keys and class names/Nib objects as values.

like image 17
David Shakhbazyan Avatar answered Nov 09 '22 04:11

David Shakhbazyan


extension UITableView {

var registeredNibs: [String: UINib] {
    let dict = value(forKey: "_nibMap") as? [String: UINib]
    return dict ?? [:]
}

var registeredClasses: [String: Any] {
    let dict = value(forKey: "_cellClassDict") as? [String: Any]
    return dict ?? [:]
}
}
like image 4
SeRG1k Avatar answered Nov 09 '22 04:11

SeRG1k