안녕하세요 WindowHyeok입니다. 오늘은 Protocol과 extension을 활용해서 깔끔하게 Cell을 재사용하는 방법에 대해 간단히 설명드리고자 합니다.
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "등록할 cell을 구별할수 있는 식별자 이름")
extension MainReviewViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: ReviewListTableViewCell.identifier, for: indexPath) as! ReviewListTableViewCell
return cell
}
}
일반적으로 뷰(table, collection)에서 우리는 보통 위의 코드와 같은 방식으로 cell을 초기화 하여 사용합니다.
이러한 방식으로 사용하게 될 경우
1. cell의 reuseIdentifier를 설정하는 과정에서 휴먼 에러가 자주 발생
2. 개인적으론 자주 똑같은 패턴으로 쓰다 보니 위처럼 작성해서 쓰는것도 매우 번거롭게 느껴짐..(지극히 개인적)
3. 여러 팀들의 코딩 컨벤션을 참고하여 한줄당 글자수 120개를 지키고 있는데, 기존 방식의 경우 글자수를 지키지 못해 강제로 줄을 넘겨 띄어쓰기를 하게 되면서 코드 가독성이 떨어짐.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: ReviewListTableViewCell.identifier,
for: indexPath
) as! ReviewListTableViewCell
return cell
}
protocol Reusable {
static var reuseIdentifier: String { get }
}
extension Reusable {
static var reuseIdentifier: String {
return String(describing: self)
}
}
extension UITableViewCell: Reusable {}
extension UICollectionViewCell: Reusable {}
extension UITableView {
func register<T: UITableViewCell>(_: T.Type) {
register(T.self, forCellReuseIdentifier: T.reuseIdentifier)
}
func cell<T: UITableViewCell>(_: T.Type, indexPath: IndexPath) -> T {
guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T else {
print("cell이 정상적으로 생성되지 않았습니다. register 부분을 확인해야함")
return T()
}
return cell
}
}
기존의 문제점을 해결한 간단하게 Cell 을 재사용할수있도록 익스텐션과 제너릭을 사용해서 작성해본 예시.
//1. 식별자 사용을 위한 Reusable Protocol
protocol Reusable {
static var reuseIdentifier: String { get }
}
extension Reusable {
static var reuseIdentifier: String {
return String(describing: self)
}
}
//2. UITableViewCell 이 Reusable Protocol 채택
extension UITableViewCell: Reusable {}
//3. UITableView에서 Reusable Protocol을 채택한 UITableViewCell의 reuseIdentifier를 활용하여 Cell을 간단하게 사용할수 있는 register, cell 메서드 작성
extension UITableView {
func register<T: UITableViewCell>(_: T.Type) {
register(T.self, forCellReuseIdentifier: T.reuseIdentifier)
}
func cell<T: UITableViewCell>(_: T.Type, indexPath: IndexPath) -> T {
guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T else {
print("cell이 정상적으로 생성되지 않았습니다. register 부분을 확인해야함")
return T()
}
return cell
}
}
사용되었던 코드의 흐름을 정리해보았습니다.
UICollectionView도 거의 똑같은 방식으로 구현하여 사용하고 있습니다.
// 기존 Cell 사용 방식
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: ReviewListTableViewCell.identifier, for: indexPath) as! ReviewListTableViewCell
return cell
}
// 더욱더 간단하게 사용 가능. 코드가 많이 줄었습니다 😀
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.cell(ReviewListTableViewCell.self, indexPath: indexPath)
return cell
}
이런 단순 반복되는 코드들을 더 간단하고 효율적으로 작성될때 뭔가 뿌듯함을 많이 느낄수 있는거 같아요.
Protocol과 제네릭을 사용하니 아주 여러개의 타입에 대해서하나의 메서드로 유용하게 대응할수 있는 점을 몸으로 확실히 느낀거 같습니다.
관련 공부도 많이 되서 좋은 경험인거 같습니다. 감사합니다.