iOS 앱을 개발하면서 UITableView나 UICollectionView를 다룰 때 우리는 항상 IndexPath라는 객체를 마주하게 된다.
델리게이트 메서드에서 특정 셀을 지칭할 때나, 데이터를 꺼내올 때 indexPath.row 혹은 indexPath.item을 사용한다.
그런데 코드를 작성하다 보면 궁금증이 생긴다. "row와 item은 결과적으로 같은 숫자를 반환하는 것 같은데, 왜 굳이 나누어 놓은 걸까?"
단순히 동작만 한다고 해서 넘어가기엔 찝찝한 이 차이점에 대해 명확히 정리하고, 왜 구분해서 사용해야 하는지 그 이유를 파헤쳐보자.
IndexPath는 Foundation 프레임워크에 정의된 구조체로, 중첩된 배열의 특정 요소에 접근하기 위한 경로(Path)를 나타낸다.
UIKit 환경에서 row와 item의 가장 큰 차이는 사용되는 프레임워크와 의미론적 맥락에 있다.
IndexPath는 단순히 두 개의 숫자(Section, Row/Item)를 담는 그릇이 아니다. 본래 Foundation 프레임워크에 속해 있으며, 트리 구조에서 특정 노드에 도달하기 위한 인덱스들의 배열을 나타낸다.
iOS에서는 주로 2개의 계층(Section과 그 안의 Index)을 사용하지만, 이론적으로는 [0, 1, 2, 1]처럼 다차원의 경로를 표현할 수도 있다. 우리가 흔히 사용하는 .row나 .item은 UIKit이 개발자의 편의를 위해 IndexPath에 추가한 Extension(확장) 속성이다.
두 속성은 기술적으로 동일한 위치의 인덱스(두 번째 인덱스)를 반환하지만, 사용되는 목적지가 다르다.
| 속성 | 대상 컨트롤 | 의미적 배경 |
|---|---|---|
| row | UITableView | 수직으로 쌓이는 '행'의 개념 |
| item | UICollectionView | 자유로운 배치 속의 '항목' 개념 |
테이블 뷰는 정보를 위에서 아래로, 즉 '줄(Row)' 단위로 나열한다. 따라서 특정 데이터를 지칭할 때 "몇 번째 줄인가?"를 묻는 것이 자연스럽다.
컬렉션 뷰는 테이블 뷰보다 훨씬 유연하다. 수직, 수평은 물론이고 그리드나 복잡한 커스텀 레이아웃을 가질 수 있다. 이때는 단순히 '줄'이라고 표현하기 어렵기 때문에, 컬렉션 안의 '개별 아이템'이라는 보다 포괄적인 용어를 사용한다.
구조적으로 row와 item은 모두 indexPath.index(at: 1)을 반환한다. 즉, row 대신 item을 쓴다고 해서 앱이 크래시가 나거나 동작이 틀어지지는 않는다. 그럼에도 우리가 이를 엄격히 구분해야 하는 이유는 다음과 같다.
코드는 단순히 기계가 읽는 것이 아니라 사람이 읽는 것이다. UITableView의 소스 코드에서 item이라는 표현을 발견한다면, 읽는 사람은 "이게 컬렉션 뷰와 관련된 로직인가?"라며 혼란을 겪을 수 있다. 해당 UI 컴포넌트의 성격에 맞는 용어를 사용하는 것이 가독성의 기본이다.
Apple의 공식 API 가이드를 보면, UITableViewDataSource에서는 row를, UICollectionViewDataSource에서는 item을 매개변수 이름으로 명시하고 있다.
// UITableView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
// UICollectionView
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
프레임워크 설계자가 의도한 방향을 따르는 것은 향후 유지보수와 협업에서 불필요한 논쟁을 줄여준다.
현재는 두 값이 같지만, 만약 미래의 특정 프레임워크에서 row와 item이 가리키는 내부 인덱스 위치가 달라지거나 별도의 로직이 추가된다면 어떻게 될까? 관례를 무시하고 섞어서 쓴 코드는 잠재적인 버그 폭탄이 될 수 있다.
결국 row와 item의 차이는 "어디에 담긴 데이터를 부르는가"에 대한 약속이다.
row를 사용하자.item을 사용하자.이러한 사소한 디테일을 지키는 것이 '돌아가기만 하는 코드'를 짜는 초보와 '의도가 명확한 코드'를 짜는 시니어 개발자를 가르는 한 끗 차이라고 생각한다.
공부를 시작했을 땐 "왜 똑같은 걸 두 개나 만들어서 귀찮게 하나" 싶었지만,
API 설계를 들여다보니 각 UI 컴포넌트의 정체성을 살리기 위한 Apple의 세심한 배려(?)가 느껴졌다.
앞으로는 헷갈리지 않고 목적에 맞게 잘 사용해야겠다고 생각했다.
indexPath.section은 공통이라 다행이다. 이것까지 달랐으면 정말...