+ 제네릭(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를 사용하여 특정 타입의 UICollectionViewCell을 UICollectionView에 등록하고 있다.
- T: UICollectionViewCell 부분은 제네릭 타입 T가 UICollectionViewCell을 상속받는 타입이어야 한다는 제약을 추가한다. 즉, 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 부분은 제네릭 타입 T가 UICollectionViewCell을 상속받는 타입이어야 한다는 제약을 추가한다.
- 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 반환. 런타임 오류를 발생시키지 않으므로, 실패할 가능성이 있을 때 사용해야 한다.
제네릭의 이점
- 타입 안전성: 제네릭을 사용하면 타입 안전성을 유지할 수 있다. → 잘못된 타입이 전달되거나 반환되는 것을 방지한다.
- 재사용성: 제네릭을 사용하면 다양한 타입과 함께 작동할 수 있는 재사용 가능한 코드를 작성할 수 있다.
- 유연성: 제네릭을 사용하면 함수나 타입이 여러 다른 타입과 함께 작동할 수 있도록 유연성을 높일 수 있다.
'iOS 앱 개발자 프로젝트' 카테고리의 다른 글
[iOS] 옵션 선택을 위한 picker 버튼 만들기 (0) | 2024.06.05 |
---|---|
[iOS] YZCenterFlowLayout 이해하기 (0) | 2024.06.04 |
[iOS] UICollectionView 내의 Carousel UI 수정하기 (2) (0) | 2024.06.03 |
[iOS] UICollectionView 내의 Carousel UI 수정하기 (1) (0) | 2024.06.03 |
[iOS] UICollectionViewCell 안에 UICollectionView 넣기 (0) | 2024.06.02 |