
레이아웃 정합성(Layout Consistency)이란 UIKit이 UICollectionView를 화면에 그리기 위해 내부적으로 유지하고 있는 데이터 구조와 실제 데이터가 '서로 맞아떨어지는 상태'를 의미한다.
UICollectionView는 셀을 그릴 때 단순히 그리는 것이 아니다. 내부적으로 "섹션 몇 개, 각 섹션에 셀 몇 개, 셀의 위치, 크기"를 전부 계산해서 기억해둔다. 이를 레이아웃 캐시(layout cache)라고 한다.
UICollectionView는 레이아웃을 그리기 전에:
layoutSubviews()나 reloadData() 전 "지금 섹션 몇 개야? 각 섹션에 아이템 몇 개야?"를 먼저 물어본다
섹션 &아이템 수 테이블을 만들고 레이아웃 캐시를 구성한다
Compositional Layout은 레이아웃을 '전제 조건'으로 계산해두고 이후 변화에 따라 animation을 적용한다.
각 섹션의 그룹/아이템 수, 크기, spacing, scroll type 등 훨씬 더 복잡한 레이아웃 정보를 미리 계산해두기 때문에, 중간에 하나라도 꼬이면 전체 섹션이 다 깨질 수 있다.
전체 UICollectionView의 layout을 미리 캐싱해두고, insert, delete, reload 같은 변화가 생기면 해당 변화량을 레이아웃에 덧셈 방식으로 적용한다.
예를 들어 UIKit이 이렇게 기억하고 있다고 하자:
Section 0 → 5개
Section 1 → 0개
Section 2 → 3개
개발자가 insertItems(at: [IndexPath(item: 0, section: 1)])을 호출하면
UIKit은 이렇게 생각한다:
"잠깐… 너 방금 전에 Section 1엔 아무것도 없다고 했잖아? 그런데 item 0을 넣는다고?" "그럼 기존 상태랑 안 맞는데? → 레이아웃 깨질 수도 있어!"
→ Crash or layout 오류 발생!
UIKit이 Compositional Layout을 설계할 때 고려한 원칙 중 하나는:
"초기 상태에서 셀 개수가 0인 섹션은 렌더링 대상이 아니다."
즉, 셀이 없으면:
총 책임자: UICollectionViewCompositionalLayout
하위 책임자들: 각 Section 레이아웃 정보
"처음에 0개였던 섹션"
UICollectionView에서 "레이아웃이 한 번도 만들어진 적 없는 섹션"은 시스템적으로 접근조차 불가능하다. 그걸 다시 활성화하려면 반드시 reloadData()로 전체 초기화를 해야 한다.
초기 layout pass 시점에서 "어떤 section이 비어 있다"고 판정되면, 그 이후에 해당 섹션에 데이터를 추가해도 layout은 무시하거나 crash를 발생시킨다. 그걸 막으려면 모든 section이 준비된 시점에서 한 번에 reloadData()를 해줘야 한다.
그래서 실제로 0개 가 되지않게 이런식으로 스켈레톤 셀을 보여주고, 실제 데이터가 들어오면 교체하는 방식을 활용한다고 한다.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0: return nowPlayingMovies.isEmpty ? 1 : nowPlayingMovies.count // 로딩 셀 1개
case 1: return upcomingMovies.isEmpty ? 1 : upcomingMovies.count
case 2: return popularMovies.isEmpty ? 1 : popularMovies.count
default: return 0
}
}
이렇게 하면하면 문제가 생기지 않는다