← 홈으로
UIKit · Scrolling · Q&A

ScrollView · TableView · CollectionView — 내 질문 Q&A

2026-06-21 스크롤뷰 학습 중 주인님이 던진 질문 + 답변을 그대로 모았다. 정리된 지식은 원리 & 심화 문서 참고.

Q&A 152026-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보다 커야 스크롤).

originsize
frame(20,30)(300,500)
bounds(0,0)(300,500) 동일
contentSize(300,2000)

contentInset은 스크롤뷰와 콘텐츠 사이 여백? 최하단이 왜 530?

✅ 콘텐츠 둘레 여백 → 스크롤 범위를 늘림. (bounds500, content1000, top50·bottom30 기준)

최상단 offset.y = -50 // top inset만큼 더 위로 최하단 offset.y = 1000 - 500 + 30 = 530 // 끝에 여백30 덧붙여 더 내림

bottom inset = 콘텐츠 끝에 빈 종이 30 덧붙여 30 더 스크롤 가능. 키보드(300)가 가리면 bottom=300으로 마지막 콘텐츠를 위로 올림. iOS 11+ adjustedContentInset=contentInset+safeArea.

contentLayoutGuide/frameLayoutGuide 동작 원리 (SnapKit)? 마지막 bottom 핀이 왜 필요?

contentLayoutGuide=contentSize 결정(콘텐츠 4변), frameLayoutGuide=보이는 폭(width 고정→가로 스크롤 방지).

contentView.snp.makeConstraints { $0.edges.equalTo(scrollView.contentLayoutGuide) // contentSize $0.width.equalTo(scrollView.frameLayoutGuide) // 가로 스크롤 방지 } lastView.snp.bottom.equalToSuperview() // ★ 높이 확정

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 필요. 비유: 사서에게 "최종 책장 모습"을 주면 알아서 정리.

신규는 Diffable 권장(표준화 추세), 레거시엔 전통(reloadData/performBatchUpdates) 혼재 → 5년차면 둘 다.

moveRow(at: c, to: d)에서 c, d는? 예시?

둘 다 IndexPath(section+row). c=원래 위치(from), d=목표 위치(to).

// ["사과","바나나","체리","딸기"] — 바나나(1)를 3으로 let moved = items.remove(at: 1); items.insert(moved, at: 3) // 데이터 먼저 tableView.moveRow(at: IndexPath(row:1,section:0), to: IndexPath(row:3,section:0))

드래그 재정렬이면 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).

관련 문서