본문 바로가기
Swift/UIKit

UIKit: TableView, CollectionView register, dequeue 셀 식별자

by songmoro 2025. 7. 31.

문제점

테이블 뷰/컬렉션 뷰에서 셀을 사용할 때 register, dequeue 하는 과정이 필요하다.
이때 셀 식별자를 사용하는데, String 값으로 관리하다 보니 "Cell"이라는 식별자를 "CEll"로 입력하거나 "Cel"로 입력하는 등 단순 실수로 인해 문제가 발생할 수 있다.

 

 

import UIKit
import SnapKit

class Cell: UITableViewCell {
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        backgroundColor = .systemBrown
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    let tableView = UITableView()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(tableView)

        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(Cell.self, forCellReuseIdentifier: "Cell")

        tableView.snp.makeConstraints {
            $0.edges.equalToSuperview(\.safeAreaLayoutGuide)
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        return cell
    }
}

 

개선방안 1

그래서 타이핑 실수로 인해 문제가 발생하지 않게끔 Cell 식별자를 관리하는 모델을 정의해 사용할 수 있다.

struct CellIdentifier {
    static let customCell1 = "CustomCell1"
    static let customCell2 = "CustomCell2"
    static let customCell3 = "CustomCell3"
}

 

이러한 방식으로 관리하던 도중, 해당 모델이 항상 메모리에 남아있는 필요가 없다고 생각하기도 하고 동시에 이 또한 문자열을 통해 수동으로 관리하는 방식이라 에러가 생길 수 있다고 판단

 

개선방안 2

일전에 print를 공부하면서 학습한 String(describing:)를 통해 개선할 수 있다고 판단

protocol IsIdentifiable: AnyObject {
    static var identifier: String { get }
}

extension IsIdentifiable {
    static var identifier: String {
        String(describing: Self.self)
    }
}

 

register, dequeue에는 String 값이 필요한데, 이를 identifier라는 메서드를 사용해 반환하도록 한다.
identifier는 String(describing:)을 사용하며 Self.self로 Self에 대한 타입을 String으로 보여줄 수 있도록 했음

->

 

 

register, dequeue는 아래와 같이 사용


class VC: UIViewController {
// ...
// 셀 등록
tableView.register(Cell.self, forCellReuseIdentifier: Cell.identifier)
// ...
// 셀 디큐
tableView.dequeueReusableCell(withIdentifier: Cell.identifier, for: indexPath)
// ...
}

 

추가

register와 dequeue 모두 Cell 타입 하나로 필요한 정보를 모두 얻을 수 있다.
따라서, extension을 통해 이 함수를 확장 시킬 수 있게 됨

 

->

extension UICollectionView {
    func register(_ cellClass: (UICollectionViewCell & IsIdentifiable).Type) {
        self.register(cellClass, forCellWithReuseIdentifier: cellClass.identifier)
    }

    func dequeueReusableCell(_ cellClass: (UICollectionViewCell & IsIdentifiable).Type, for indexPath: IndexPath) -> (AnyObject & IsIdentifiable) {
        self.dequeueReusableCell(withReuseIdentifier: cellClass.identifier, for: indexPath) as! (AnyObject & IsIdentifiable)
    }
}

extension UITableView {
    func register(_ cellClass: (UITableViewCell & IsIdentifiable).Type) {
        self.register(cellClass, forCellReuseIdentifier: cellClass.identifier)
    }

    func dequeueReusableCell(_ cellClass: (UITableViewCell & IsIdentifiable).Type, for indexPath: IndexPath) -> UITableViewCell {
        self.dequeueReusableCell(withIdentifier: cellClass.identifier, for: indexPath)
    }
}

 

참고

https://songmoro.tistory.com/217