2020/03/16 - [UIKit] - [UIKit] UITableView의 indexPathForRow(at:) 오차에 대한 디버깅
위 글에서 언급했던, Generic Cell Configurator에 대해 다루고자 합니다. 중복되는 내용이 포함되어 있습니다.
iOS 개발자라면 UITableView, UICollectionView를 사용하며 많은 시간을 보낼 것이라고 생각합니다.
한 화면에서 여러 종류의 Cell을 사용하거나, 한 가지 데이터 타입으로 여러 종류의 Cell을 표현하고자 할 경우, 머리가 아팠던 경험들이 있을 거라고 생각합니다. (적어도 저는 그랬습니다...)
보통 Cell의 타입에 따라 cellForRowAt 함수에서 Cell에 해당하는 뷰들을 불러오고, 그 뷰들에 맞게 data를 세팅해주는 방식을 사용합니다. 이 방식을 사용하게 되면, Cell을 사용하는 종류가 많아질수록 분기 처리해야 하는 부분이 많아지게 됩니다.
그 외에 다른 문제점들이 있다고 판단하여, configurator라는 개념을 사용하여, configurator에 view를 설정하는 방식을 사용하게 되었습니다.
Generic을 활용하여 아래와 같이 보다 심플하게 다양한 Cell들을 사용할 수 있습니다.
사용하는 이유는 다음과 같습니다.
- 불필요한 분기 처리를 줄이는 것
- 타입 캐스팅을 줄이는 것
- Cell이 Data Type에 종속적이지 않은 것
- 재사용이 가능한 코드
만드는 과정에 대해 설명하겠습니다.
Generic 코드를 사용하면 정의한 요구 사항에 따라 유형에 종속되지 않고, 유연하며 재사용 가능한 기능을 개발할 수 있습니다.
중복을 피하고 명확하고 추상적인 방식으로 표현하는 코드를 작성할 수 있습니다.
Generic 프로그래밍은 상용구 코드를 피하는 훌륭한 방법이며 컴파일 시간 동안 오류를 검출하는 데 도움이 됩니다.
Apple Document
1. 먼저 TableViewCell, CollectionViewCell의 contentView에 해당하는 view가 채택해야 할,
프로토콜입니다.
2. 다음으로 Cell이 채택해야 할 프로토콜과
ContentView안에 래핑 하여 사용할 수 있는 Generic Cell을 구성할 수 있습니다.
3. 이제 Generic Cell Configurator를 작성할 수 있습니다.
세부 내용은 아래 다이어그램과 함께 설명하도록 하겠습니다.
ConfigurableContainerView : Cell 내부 View로 붙이기 위해 Custom View에서 채택해야 하는 프로토콜입니다. 채택하여 구현할 경우 Delegate 및 DataType을 정의해야 합니다.
ConfigurableCell : TableViewCell, CollectionViewCell의 타입과 상관없으며, Cell에 필요한 view는 ConfigurableContainerView 타입이며, 사용할 경우 ViewType의 정의가 필요합니다.
GenericContainerTableCell : ConfigurableCell 프로토콜을 채택하여 TableViewCell을 구성하는 일반 클래스입니다. ConfigurableCell와 마찬가지로 사용할 경우 ViewType의 정의가 필요합니다. ConfigurableContainerView를 채택한 CustomView가 그 정의에 해당합니다.
CellConfigurator : 데이터 타입을 정의하지 않고, Generic 클래스를 소유할 수 없으므로, 사용 관점에서 이 프로토콜이 필요합니다.
TableCellConfigurator : CellType에 대한 유형 제한 조건이 있는 Generic 클래스입니다. Cell을 구성할 때, view를 받아와서 data 설정 과정을 거칩니다.
이제 ViewModel을 수정하여 적용할 수 있습니다.
Component는 Cell, Configurator 타입 별칭들을 모아놓은 구조체입니다.
TitleView, ProfileView, ContentView, DateView는 ConfigurableContainerView를 채택한 UIView 타입입니다.
아래와 같이 TableView에 Cell을 regist 할 수 있습니다.
https://medium.com/chili-labs/configuring-multiple-cells-with-generics-in-swift-dcd5e209ba16
위 포스팅과의 차이점은 첫 번째로, delegate를 통해 Cell의 user interaction 등을 위임 처리할 수 있도록 설정한 것이 있습니다. Cell의 user interaction 등에 따른 위임 처리가 필요하다고 판단하여 delegate를 설정하는 과정을 추가했습니다.
CellConfigurator는 사용 관점에서 필요하기 때문에 Concrete 한 정의를 필요로 해서는 안됩니다. 그렇기 때문에 delegate 프로토콜을 만족하는 객체는 특정 타입을 지정할 수 없다고 판단하여, AnyObject 타입으로 받고 내부에서 판단하도록 구현했습니다.
Table / Collection Cell Configurator 내부에서 delegate를 받아서 CellConfigurator에서 configurable cell을 configure 할 때에, delegate를 넘겨주는 방식도 있지만, 이는 data 로직을 담당하는 부분에서 위임 처리하는 객체 또한 정의해야 하는 불필요함이 존재합니다.
다음으로는 Cell에 국한되지 않고, View로 개념을 확장하여 Configurable Container View를 채택한 View를 만들게 되면 TableViewCell, CollectionViewCell 그리고 일반적인 View에서도 사용 가능합니다. 이는 하나의 View(ConfigurableContainerView)를 만듦으로써, 다양하게 사용할 수 있는 여지를 만들어 주며, 재사용성을 더 높일 수 있습니다.
다음은 ProfileView를 재사용하여 일반 View로 사용한 경우입니다.
'UIKit' 카테고리의 다른 글
[UIKit] LSP 위반 케이스 (Forced Unwrapping의 위험성) (0) | 2021.06.05 |
---|---|
[UIKit] systemLayoutSizeFitting 사용 시, 주의 사항 (0) | 2020.10.29 |
[UIKit] Dynamic cell sizing - systemLayoutSizeFitting (1) | 2020.10.29 |
[UIKit] CollectionView - cell reuse시 주의해야 할 점 (0) | 2020.10.26 |
[UIKit] UITableView의 indexPathForRow(at:) 오차에 대한 디버깅 (2) | 2020.03.16 |