๐ŸŽจ iOS ๋ทฐ์˜ ๋“œ๋กœ์ž‰ ์‚ฌ์ดํด (View Drawing Cycle)

SeBinยท2025๋…„ 1์›” 28์ผ
post-thumbnail

์ฝ”๋“œ๋ฒ ์ด์Šค๋กœ UI๋ฅผ ๊ทธ๋ฆฌ๋‹ค๊ฐ€ cornerRadius๊ฐ€ ์ ์šฉ ๋˜์ง€ ์•Š์•˜๋˜ ๊ฒฝํ—˜์ด ์žˆ์ง€ ์•Š์œผ์‹ ๊ฐ€์š”?

์ด๋Š” View์˜ Drawing Cycle๊ณผ ์—ฐ๊ด€์ด ์žˆ๋Š”๋ฐ์š”, UI๋ฅผ ์ œ๋Œ€๋กœ ํ•ธ๋“ค๋งํ•˜๊ธฐ ์œ„ํ•ด์„œ View Drawing Cycle์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

๐Ÿ” Drawing Cycle์ด๋ž€

๋ทฐ๊ฐ€ ๋กœ๋“œ ๋˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ์ด ์žˆ์„๋•Œ ํ™”๋ฉด์— ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œํ˜„๋˜์–ด ๊ทธ๋ ค์ง€๋Š” ์‚ฌ์ดํด

๋ทฐ๋Š” Constraints(์ œ์•ฝ์กฐ๊ฑด)์„ ์ด์šฉํ•ด์„œ Layout(Size, Position)์„ ๊ฒฐ์ •ํ•˜๊ณ  ๊ทธ Layout์„ ํ† ๋Œ€๋กœ UI๋ฅผ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.

UIKit์—์„œ๋Š” ์ด ๊ณผ์ •์„ Drawing Cycle์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

๐Ÿ” Drawing Cycle์˜ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ˆœ์„œ

updateConstraints() โ†’ layoutSubviews() โ†’ draw(_:)

์ด ๋ฉ”์„œ๋“œ๋“ค์˜ ๊ณตํ†ต์ ์€ ์‹œ์Šคํ…œ ์‚ฌ์ดํด์— ๋งž๊ฒŒ ํ˜ธ์ถœ์ด ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ ์ง์ ‘ ํ˜ธ์ถœํ•ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ์ง์ ‘ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด ์ •์ƒ์ ์ธ ํƒ€์ด๋ฐ์— ํ˜ธ์ถœ๋˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ฏ€๋กœ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์˜ค๋ฒ„๋ผ์ด๋“œ ๋ฐ super ํ˜ธ์ถœ์„ ํ•˜๊ฑฐ๋‚˜, ์˜ˆ์•ฝ ๋ฉ”์„œ๋“œ๋กœ ์‹œ์Šคํ…œ์ด ์ ์ ˆํ•œ ์‹œ์ ์— ํ˜ธ์ถœํ•˜๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

1. updateConstraints()

๋ทฐ์˜ Constraints๋ฅผ ์—…๋ฐ์ดํŠธ ํ•ด์ค๋‹ˆ๋‹ค.
ํ˜„์žฌ ๊ธฐ๊ธฐ์˜ ํ™”๋ฉด ํฌ๊ธฐ์™€ ๋ถ€๋ชจ ๋ทฐ์˜ ํฌ๊ธฐ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ฐฑ์‹ ๋ฉ๋‹ˆ๋‹ค.

override func updateConstraints() {
    // ์ปค์Šคํ…€ ์ œ์•ฝ ์กฐ๊ฑด ์—…๋ฐ์ดํŠธ
    super.updateConstraints()
}
  • ๋ฐ˜๋“œ์‹œ ๋งˆ์ง€๋ง‰์— super.updateConstraints()๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ง์ ‘ ํ˜ธ์ถœํ•˜๋ฉด ์•ˆ๋˜๊ณ  ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜๊ฑฐ๋‚˜ ์˜ˆ์•ฝํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ setNeedsUpdateConstraints() / updateConstraintsIfNedded() ๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

2. layoutSubviews()

ํ•˜์œ„ ๋ทฐ์˜ ๋ ˆ์ด์•„์›ƒ(์œ„์น˜, ํฌ๊ธฐ)๋ฅผ ์žฌ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
๋ทฐ ๋“ค์˜ ๋ ˆ์ด์•„์›ƒ ํ”„๋ ˆ์ž„์ด ์ •ํ•ด์ง€๋Š” ์‹œ๊ธฐ์ž…๋‹ˆ๋‹ค.

override func layoutSubviews() {
    super.layoutSubviews()
    // ๋ ˆ์ด์•„์›ƒ ์—…๋ฐ์ดํŠธ
}
  • ์ด๋•Œ ํ”„๋ ˆ์ž„ ๊ด€๋ จ ์ž‘์—…(frame.height/2 ๋งŒํผ์˜ corenrRadius ์ ์šฉ ๋“ฑ)์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.
  • ํ˜ธ์ถœํ•˜๋ฉด ํ•ด๋‹น ๋ทฐ์˜ ๋ชจ๋“  ์„œ๋ธŒ๋ทฐ๋“ค์ด layoutSubviews()๋ฅผ ์—ฐ๋‹ฌ์•„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  • ์†Œ๋ชจ ๋น„์šฉ์ด ๋„ˆ๋ฌด ํฌ๊ธฐ ๋•Œ๋ฌธ์— ์ง์ ‘ ํ˜ธ์ถœ์€ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • layoutSubviews๊ฐ€ ํ˜ธ์ถœ๋˜๋„๋ก ์˜ˆ์•ฝํ•˜๋Š” ๋ฉ”์„œ๋“œ setNeedsLayout() / layoutIfNeeded()๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ณ , ์ถ”๊ฐ€์ ์ธ ์—…๋ฐ์ดํŠธ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์˜ค๋ฒ„๋ผ์ด๋“œํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

3. draw(_ :)

๋ทฐ์˜ ์‹ค์ œ ์ฝ˜ํ…์ธ (๊ทธ๋ž˜ํ”ฝ ์š”์†Œ)๋ฅผ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.

override func draw(_ rect: CGRect) {
    super.draw(rect)
    // ์ปค์Šคํ…€ ๊ทธ๋ฆฌ๊ธฐ ์ฝ”๋“œ
}
  • UIView์˜ ๊ธฐ๋ณธ์ ์ธ ์š”์†Œ(์ƒ‰์ƒ, ์ฝ”๋„ˆ ๋ฐ˜๊ฒฝ ๋“ฑ)๋Š” draw(_:)๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.
  • draw ์—ญ์‹œ ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  setNeedsDisplay() ๋กœ ์˜ˆ์•ฝํ•˜๊ฑฐ๋‚˜ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ ์˜ˆ์•ฝํ•˜๋Š” ๋ฉ”์„œ๋“œ๋“ค

setNeedsUpdateConstraints, updateConstraintsIfNeeded

  • updateConstraints๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก ์˜ˆ์•ฝํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.

setNeedsLayout, layoutIfNeeded

  • layoutSubviews๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก ์˜ˆ์•ฝํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.

setNeedsDisplay

  • draw๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก ์˜ˆ์•ฝํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.
  • View์˜ ์‹ค์ œ ์ปจํ…์ธ ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ,View๋ฅผ ๋‹ค์‹œ ๊ทธ๋ ค์•ผํ•จ์„ ์‹œ์Šคํ…œ์— ์•Œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„ ๋ฉ”์„œ๋“œ๋“ค์€ ์ด๋ฆ„์ด ๋น„์Šทํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋™์ž‘ ์—ญ์‹œ ๋น„์Šทํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ setNeedsLayout, layoutIfNeeded๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์„ค๋ช… ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

setNeedsLayout

setNeedsUpdateConstraints, setNeedsDisplay๋„ ๋น„์Šทํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ทฐ ์—…๋ฐ์ดํŠธ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  trigger ํ•˜๋Š” ์—ญํ• ์ž…๋‹ˆ๋‹ค.
  • ๋ ˆ์ด์•„์›ƒ์„ ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š๊ณ , ๋‹ค์Œ ์—…๋ฐ์ดํŠธ ์ฃผ๊ธฐ ๋•Œ layoutSubviews๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜์—ฌ ์—…๋ฐ์ดํŠธ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋‹น์žฅ ๋ ˆ์ด์•„์›ƒ์„ ๋ฐ”๊ฟ€ ํ•„์š”๊ฐ€ ์—†์„ ๋•Œ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ณ , ๋ถˆํ•„์š”ํ•œ ๋ ˆ์ด์•„์›ƒ ์—ฐ์‚ฐ์„ ๋ง‰์•„ ์„ฑ๋Šฅ ํ–ฅ์ƒ์— ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.
func updateCircle(center: CGPoint, radius: CGFloat) {
    self.center = center
    self.radius = radius
    
    setNeedsLayout() // ๋ ˆ์ด์•„์›ƒ ์—…๋ฐ์ดํŠธ ์˜ˆ์•ฝ
    setNeedsDisplay() // ๋‹ค์‹œ ๊ทธ๋ฆฌ๊ธฐ ์˜ˆ์•ฝ
}

layoutIfNeeded

updateConstraintsIfNeeded ๋„ ๋น„์Šทํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ ˆ์ด์•„์›ƒ์„ ์ฆ‰์‹œ ์—…๋ฐ์ดํŠธ ํ•ด์ฃผ๋ฉฐ ๋™๊ธฐ์ ์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  • ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐ”๋กœ ์ ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ(ex. ์• ๋‹ˆ๋ฉ”์ด์…˜) ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • ๋ณด๋ฅ˜ ์ค‘์ธ ๋ ˆ์ด์•„์›ƒ ์—…๋ฐ์ดํŠธ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์ฝœ๋ฐฑ์„ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  ์ข…๋ฃŒ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ ํ–ฅ์ƒ์— ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.
UIView.animate(withDuration: 0.3) {
    myView.frame.size = CGSize(width: 200, height: 200)
    myView.layoutIfNeeded()
}

โžก๏ธ ๊ฐ View๋“ค๊ฐ„์˜ ์—ฐ์‡„์  ํ˜ธ์ถœ ์ˆœ์„œ

๋ทฐ๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ ๊ฒน์ณ ์žˆ์„ ๋•Œ, updateConstraints์™€ layoutSubviews์˜ ํ˜ธ์ถœ ์ˆœ์„œ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜คํ† ๋ ˆ์ด์•„์›ƒ์€ ํ•˜์œ„ ๋ทฐ โžก๏ธ ์ƒ์œ„ ๋ทฐ ์ˆœ์„œ๋กœ, ๊ทธ ํ›„์— ย ๋ทฐ๋“ค์˜ ๋ฐฐ์น˜๋ฅผ ์ƒ์œ„ ๋ทฐ โžก๏ธ ํ•˜์œ„ ๋ทฐย ์ˆœ์„œ๋กœ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์•ˆ์ชฝ ๋ถ€ํ„ฐ ์ œ์•ฝ์กฐ๊ฑด์„ ์žก์•„๊ฐ€๊ณ , ๋‹ค์‹œ ๋ฐ”๊นฅ์ชฝ๋ถ€ํ„ฐ ์œ„์น˜์™€ ์‚ฌ์ด์ฆˆ๋ฅผ ์žก์•„๊ฐ€๋Š” ๊ฒƒ์ด์ฃ .

  • updateConstraints - ํ•˜์œ„ย โžก๏ธย ์ƒ์œ„
  • layoutSubviews - ์ƒ์œ„ย โžก๏ธย ํ•˜์œ„

๊ทธ๋ž˜์„œ ์ „์ฒด์ ์ธ ํ˜ธ์ถœ ์ˆœ์„œ๊ฐ€ ์ด๋Ÿฐ์‹์œผ๋กœ ์ผ์–ด๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  • ํ•˜์œ„ย (updateConstraints)ย โžก๏ธย ์ค‘๊ฐ„ย (updateConstraints)ย โžก๏ธย ์ƒ์œ„ย (updateConstraints)ย โžก๏ธย ์ƒ์œ„ย (layoutSubviews)ย โžก๏ธย ์ค‘๊ฐ„ย (layoutSubviews)ย โžก๏ธย ํ•˜์œ„ย (layoutSubviews)

Drawing Cycle์— ๋Œ€ํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด์•˜๋Š”๋ฐ์š”, ์ด ๋‚ด์šฉ์€ iOS์˜ Main Run Roop์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ๊ด€๋ จ๋˜์–ด์žˆ์–ด ๋‹ค์Œ์— ์ด์™€ ๊ด€๋ จ๋œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค โ˜บ๏ธ

0๊ฐœ์˜ ๋Œ“๊ธ€