본문 바로가기

iOS 앱 개발자 프로젝트

[iOS] UICollectionView에서 제네릭으로 코드 수정하기

+ 제네릭(Generic)이란?

 

타입에 의존하지 않는 재사용 가능한 함수나 타입을 정의할 있도록 하는 기능.

제네릭을 사용하면 타입 안전성을 유지하면서도 여러 다른 타입과 함께 작동할 있는 코드를 작성할 있다. 타입 매개변수(parameter) 사용하여 특정 타입으로 작동하는 코드의 틀을 제공한다.


 

프로젝트 진행 중에 컬렉션뷰 안에 셀이 있고 그 안에 다시 새로운 뷰에서 cell로 캐로셀을 구현하다보니

셀을 등록하고 빼는 과정이 무척 혼란스러웠다. 

이때 제네릭을 써보면 쉽지 어떻겠는지 의견을 주셔서 아래의 코드처럼 extension으로 빼냈으나 이 과정을 이해하진 못했다.

선 코드 후 이해 방식으로.. 이제 하나씩 이해해 보자.

 

아래 제네릭은 UICollectionView 대한 확장을 통해 가지 기능을 추가한다. 하나는 셀을 등록하는 메서드[ register(for:) ]이고, 다른 하나는 재사용 가능한 셀을 큐에서 빼내는 메서드[ dequeueReusable(for:)  ]이다. 메서드가 제네릭으로 특정 타입의 셀과 함께 작동하도록 설계되었는데.. 

 

import UIKit

extension UICollectionView {
    func register<T: UICollectionViewCell>(for type: T.Type) {
        register(type, forCellWithReuseIdentifier: String(describing: T.self))
    }
    
    func dequeueReusable<T: UICollectionViewCell>(for indexPath: IndexPath) -> T {
        dequeueReusableCell(withReuseIdentifier: String(describing: T.self), for: indexPath) as! T
    }

 

 

 

두 메서드를 하나씩 뜯어서 살펴보면,

 

 

1. register(for:) 메서드:

 

제네릭 타입 T를 사용하여 특정 타입의 UICollectionViewCellUICollectionView에 등록하고 있다.

  • T: UICollectionViewCell 부분은 제네릭 타입 TUICollectionViewCell을 상속받는 타입이어야 한다는 제약을 추가한다. 즉, T는 반드시 UICollectionViewCell의 서브클래스여야 함을 의미한다.
  • for type: T.Type는 메서드가 T 타입의 메타 타입을 매개변수로 받는다는 것을 의미한다. 예를 들어, MyCustomCell.self와 같은 방식으로 타입을 전달할 수 있다.
  • register(type, forCellWithReuseIdentifier: String(describing: T.self)) UICollectionView 기본 제공 메서드인 register(_:forCellWithReuseIdentifier:) 호출한다. 여기서 String(describing: T.self) 클래스의 이름을 문자열로 변환하여 재사용 식별자로 사용한다. 예를 들어, MyCustomCell 클래스의 경우 식별자는 "MyCustomCell" 된.
extension UICollectionView {
    func register<T: UICollectionViewCell>(for type: T.Type) {
        register(type, forCellWithReuseIdentifier: String(describing: T.self))
    }
}

 

 

 

2. dequeueReusable(for:) 메서드

  • T: UICollectionViewCell 부분은 제네릭 타입 TUICollectionViewCell을 상속받는 타입이어야 한다는 제약을 추가한다.
  • for indexPath: IndexPath는 메서드가 IndexPath 타입의 매개변수를 받아야 한다는 것을 의미하며, 이는 셀이 위치할 인덱스 경로를 나타내고 있다.
  • dequeueReusableCell(withReuseIdentifier: String(describing: T.self), for: indexPath)UICollectionView의 기본 제공 메서드인 dequeueReusableCell(withReuseIdentifier:for:)를 호출하여 재사용 가능한 셀을 큐에서 빼낸다. 여기서도 String(describing: T.self)는 클래스 이름을 문자열로 변환하여 재사용 식별자로 사용한다.
  • as! T 빼낸 셀을 제네릭 타입 T 강제 캐스팅한다. 여기서 강제 캐스팅(as!) 만약 타입이 맞지 않으면 런타임 오류를 발생시킬 있으므로, 타입이 맞는다는 확신이 있는 경우에만 사용해야 한다.
캐스팅이란?
캐스팅은 하나의 타입을 다른 타입으로 변환하는 것.
Swift에서는 타입 캐스팅을 사용하여 특정 타입의 인스턴스를 다른 타입으로 다루거나, 특정 타입인지 확인할 수 있다.

안전한 캐스팅(as?)
as?는 안전한 캐스팅 방식.
만약 캐스팅이 실패하면 nil 반환. 런타임 오류를 발생시키지 않으므로, 실패할 가능성이 있을 때 사용해야 한다.

 

 

 


 

 

제네릭의 이점 

  • 타입 안전성: 제네릭을 사용하면 타입 안전성을 유지할 수 있다. → 잘못된 타입이 전달되거나 반환되는 것을 방지한다.
  • 재사용성: 제네릭을 사용하면 다양한 타입과 함께 작동할 수 있는 재사용 가능한 코드를 작성할 수 있다.
  • 유연성: 제네릭을 사용하면 함수나 타입이 여러 다른 타입과 함께 작동할 있도록 유연성을 높일 있다.