iOS에서 UI 변경이 바로 적용되지 않는 이유
🌀 RunLoop와 예약된 작업 처리
iOS 앱을 개발하다 보면 setNeedsLayout()
이나 setNeedsDisplay()
같은 메서드를 쓰는데,
이걸 호출해도 화면이 즉시 바뀌지 않는 경험을 한 번쯤 있습니다..
이 글에서는 왜 즉시 반영되지 않고 '예약'만 되는지, 그리고 그걸 언제 처리하는지
즉, RunLoop가 어떤 역할을 하는지를 정리해보겠습니다.
📌 예약만 하고 바로 안 되는 이유?
UIKit은 성능을 위해 UI 변경 작업을 즉시 처리하지 않고,
한 번에 모아서 처리하는 구조를 사용합니다.
이때 사용하는 시스템이 바로 RunLoop
입니다.
🔁 RunLoop란?
RunLoop는 iOS 앱이 실행되는 동안 돌아가는 이벤트 처리 루프입니다.
앱은 항상 RunLoop를 돌며 "터치, 타이머, 네트워크, UI 업데이트" 같은 다양한 이벤트를 처리합니다.
RunLoop가 처리하는 예시들:
- 터치 이벤트
- 타이머 (
Timer
) - 네트워크 응답
setNeedsLayout()
등의 UI 업데이트 예약- 오토릴리즈 풀 비우기
🔧 예시: setNeedsLayout은 왜 바로 적용되지 않을까?
view.setNeedsLayout()
// 여기선 아무 일도 안 일어남 ❌
위 코드는 단지 "나중에 레이아웃이 필요해"라고 알리는 예약일 뿐입니다.
실제 layoutSubviews()
는 RunLoop가 돌아올 때 실행됩니다.
// 다음 RunLoop 사이클에서 실행됨
-> view.updateConstraints()
-> view.layoutSubviews()
-> view.draw()
💡 예약은 왜 필요한가?
UIKit이 이렇게 동작하는 이유는 성능 최적화에 있습니다.
만약 변경마다 즉시 처리한다면?
- CPU 사용량 증가
- 화면 깜빡임
- 애니메이션 끊김
그래서 변경 요청을 하나하나 처리하지 않고, 한번에 묶어서 처리합니다.
이걸 RunLoop가 도와줍니다.
🧪 실전 예시: 즉시 변경이 필요할 때
label.text = "로딩 중..."
view.setNeedsLayout()
sleep(2)
// 여전히 "로딩 중..."이 화면에 안 나올 수 있음
이 경우엔 RunLoop
가 layoutSubviews()
를 아직 호출하지 않았기 때문에
화면에는 여전히 이전 상태가 보여질 수 있습니다.
해결 방법:
label.text = "로딩 중..."
view.layoutIfNeeded() // 지금 즉시 레이아웃 반영!
✅ 언제 예약되고, 언제 즉시 실행할까?
메서드 | 동작 방식 |
---|---|
setNeedsLayout() |
다음 RunLoop에서 레이아웃 업데이트 예약 |
setNeedsDisplay() |
다음 RunLoop에서 draw 호출 예약 |
layoutIfNeeded() |
바로 레이아웃 계산 & 적용 |
updateConstraintsIfNeeded() |
바로 제약 조건 업데이트 실행 |
🔚 마무리
UIKit은 즉시 반영보다는 예약 기반 처리를 선호합니다.
그 이유는 성능을 고려한 설계 철학 때문이며,
이를 가능하게 하는 게 바로 RunLoop라는 이벤트 루프 시스템입나다.
UI가 바로 안 바뀌는 이유를 정확히 알면,layoutIfNeeded()
나 updateConstraintsIfNeeded()
를 언제 사용해야 할지 명확해집니다.