ScrollView · TableView · CollectionView — 내 질문 Q&A
2026-06-21 스크롤뷰 학습 중 주인님이 던진 질문 + 답변을 그대로 모았다. 정리된 지식은 원리 & 심화 문서 참고.
Q&A
UIScrollView는 재사용을 안 하나? "데이터소스 기반 lazy 생성"은 cellForItem?
ScrollView는 재사용·dataSource 없음. 직접 addSubview로 넣은 뷰가 전부 메모리 상주. 재사용·dataSource·lazy 생성은 Table/Collection이 추가한 기능. "lazy 생성"=cellForItemAt이 보일 때만 dequeue+구성(보일 셀만큼만 그때그때 호출). ✅ cellForItem이 그 지점.
TableView는 레이아웃을 누가 관리해? (CollectionView는 객체에 위임이라며)
UITableView 자기 내부. 세로 1열 누적 배치가 내장(별도 객체 없음). "높이 정보"는 delegate/제약이 주고, "실제 배치(frame 계산)"는 테이블뷰 내부. CollectionView는 그 배치 로직을 UICollectionViewLayout 객체로 빼서 교체 가능하게 일반화.
bounds.origin (0,100)은 스크롤 내린 거야? 콘텐츠 고정·bounds만 이동?
✅ 아래로 100 스크롤한 상태(iOS y는 아래로 증가). 콘텐츠는 제자리 고정, scroll view가 보는 창(bounds)만 이동. 움직이는 건 frame이 아니라 bounds. contentOffset == bounds.origin. 비유: 콘텐츠=긴 두루마리(고정), bounds=미끄러지는 창문.
왼쪽20·위30에 배치하면 frame=(20,30), bounds=(0,0)?
✅ frame.origin=(20,30)(부모 기준 위치), bounds.origin=(0,0)(스크롤 전). frame과 bounds는 size가 같고 origin만 다름. contentSize는 별개(전체 콘텐츠, bounds보다 커야 스크롤).
| origin | size | |
|---|---|---|
| frame | (20,30) | (300,500) |
| bounds | (0,0) | (300,500) 동일 |
| contentSize | — | (300,2000) |
contentInset은 스크롤뷰와 콘텐츠 사이 여백? 최하단이 왜 530?
✅ 콘텐츠 둘레 여백 → 스크롤 범위를 늘림. (bounds500, content1000, top50·bottom30 기준)
bottom inset = 콘텐츠 끝에 빈 종이 30 덧붙여 30 더 스크롤 가능. 키보드(300)가 가리면 bottom=300으로 마지막 콘텐츠를 위로 올림. iOS 11+ adjustedContentInset=contentInset+safeArea.
contentLayoutGuide/frameLayoutGuide 동작 원리 (SnapKit)? 마지막 bottom 핀이 왜 필요?
contentLayoutGuide=contentSize 결정(콘텐츠 4변), frameLayoutGuide=보이는 폭(width 고정→가로 스크롤 방지).
footer.bottom == contentView.bottom은 참조가 아니라 방정식 — footer 위치가 거꾸로 contentView 높이를 정의(bottom-up). 빠뜨리면 높이 ambiguous → 스크롤 안 됨.
automaticDimension + estimatedRowHeight 자세히. 왜 contentSize를 알아야? estimated 없으면? systemLayoutSizeFitting? contentOffset 보정?
- 왜 contentSize? 스크롤바 길이·범위·셀 위치에 필요(추정이라도)
- automaticDimension = "고정값 말고 셀 제약으로 높이 계산". frame/고정값으로 주면 Auto Layout 계산 스킵(빠름·수동)
- estimated 없으면(0) 로드 시 전부 계산(1만 개=1만 번)→멈춤. 주면 추정 후 보이는 셀만 lazy
- systemLayoutSizeFitting = 제약을 풀어 "최적 높이" 계산(폭 고정·높이 최소). top~bottom 제약 완결 필요
- contentOffset 보정 = 위쪽 셀이 추정80→실제120 되면 콘텐츠 좌표가 커짐 → 같은 셀 보려면 offset도 옮겨야. 안 맞으면 점프(위로 스크롤 시 심함)
UITableViewDataSourcePrefetching은 클래스야?
❌ 프로토콜. prefetchDataSource로 연결. prefetchRowsAt(필수)/cancelPrefetchingForRowsAt(선택). cellForRow보다 일찍 데이터만 미리 준비(셀 생성 아님) → 빈 셀 깜빡임 감소. CollectionView도 동일 프로토콜.
batch update vs Diffable Data Source 쉽게? performBatchUpdates? 지금은 Diffable 쓰나?
전통: "어디 바뀜(인덱스)" 직접 알림 → 데이터 개수 안 맞으면 크래시. performBatchUpdates=여러 변경을 한 묶음·한 애니로 동시 적용.
Diffable(iOS 13+): "최종 상태(스냅샷)"를 통째로 주면 시스템이 차이(diff) 자동 계산 → 인덱스 계산·크래시 없음. Item은 Hashable 필요. 비유: 사서에게 "최종 책장 모습"을 주면 알아서 정리.
moveRow(at: c, to: d)에서 c, d는? 예시?
둘 다 IndexPath(section+row). c=원래 위치(from), d=목표 위치(to).
드래그 재정렬이면 tableView(_:moveRowAt:to:) delegate에서 배열만 맞춤(테이블은 자동 이동). 배열도 같이 안 바꾸면 크래시.
UICollectionViewLayout의 prepare/contentSize/layoutAttributesForElements/Item? zIndex? attributes 정체? frame은 CGRect?
prepare()모든 요소 위치 미리 계산·캐싱 /collectionViewContentSize전체 크기layoutAttributesForElements(in rect)그 영역 요소들 attributes(재사용 판단 주력) /layoutAttributesForItem(at:)특정 셀(애니·scrollToItem 등 필요 시)- UICollectionViewLayoutAttributes = 한 요소의 배치 속성 묶음(frame·alpha·zIndex·transform). frame은 CGRect(위치+크기)
- zIndex = 겹칠 때 앞뒤 순서(큰 값이 위). 예: sticky header가 셀 위에, 카드 덱 겹침
frame 직접 계산하면 텍스트 길어질 때 frame을 직접 늘려야 해? boundingRect·sizeThatFits가 뭐야?
✅ frame 직접 방식은 텍스트 길면 높이를 내가 계산해 frame을 직접 키워야(자동 X). 그 크기를 미리 재는 도구:
- boundingRect(NSString): "이 글자를 폭 300에 넣으면 높이 얼마?" 계산
- sizeThatFits(UIView): 라벨에게 "이 폭이면 너 얼마 필요해?" 물어봄
둘 다 표시 전에 크기를 미리 재는 줄자. 폭 고정 → 필요 높이 반환.
Auto Layout 하면 이 크기 계산을 알아서 해주나? intrinsic은 인셋도 포함? 텍스트 위아래 간격은?
✅ Auto Layout(self-sizing)이 라벨의 intrinsic content size로 자동 계산 → boundingRect 수동 불필요(numberOfLines=0 + 제약 완결 + automaticDimension 조건).
| intrinsic에 포함? | |
|---|---|
| 텍스트 위아래 간격(폰트 line height 여유) | ✅ 포함(라벨 자체 높이) |
라벨-셀 inset(top==contentView.top+8) | ❌ 별개(제약) |
그 위아래 간격은 폰트 line height(ascender/descender 여유) — 16pt 폰트면 글자 ~12, line height ~20. 줄이려면 attributed string의 lineHeightMultiple 조정. 최종 셀 높이 = intrinsic(텍스트) + 제약(inset).