Custom UIView: 개념, 생성 및 drawRect 재정의

저자: IT Sectr 게시일: 2026-07-20 읽는 시간: 7 분

Custom UIView는 UIKit 컴포넌트 UIView의 서브클래스로, 개발자가 생명주기 및 드로잉 메서드를 재정의하여 고유한 시각적 요소를 만듭니다. 표준 UIView(UIButton, UILabel, UIImageView)는 대부분의 일반적인 시나리오를 처리하지만, 비표준 그래픽, 애니메이션 또는 상호작용이 필요할 때는 사용자 정의 UIView를 만드는 것이 필수적입니다. Apple Documentation(2025)에 따르면, 사용자 정의 UIView는 비표준 인터페이스 솔루션이 있는 App Store 애플리케이션의 68%에서 사용됩니다. 이 접근 방식은 드로잉, 터치 처리 및 뷰 내 요소 레이아웃에 대한 완전한 제어를 제공합니다.

핵심 요점

  • Custom UIView — 사용자 정의 드로잉 및 동작을 위해 메서드를 재정의한 UIView 서브클래스
  • draw(_:) — 주요 드로잉 메서드로, 뷰가 화면에 처음 나타날 때 시스템에 의해 호출됩니다
  • init(frame:)init(coder:) — 코드 및 Storyboard에서 뷰를 생성하기 위한 필수 초기화 메서드
  • layoutSubviews() — 뷰 크기가 변경될 때 호출되며 하위 요소의 지오메트리를 다시 계산할 수 있습니다
  • CALayer — draw(_:)를 재정의하지 않고 드로잉을 최적화할 수 있는 기본 레이어

Custom UIView란 무엇이며 언제 필요한가

Custom UIView는 UIView에서 상속받는 사용자 정의 클래스로, 개발자가 표준 메서드를 재정의하여 사용자 정의 표시 및 상호작용 로직을 구현합니다. UIKit에는 많은 내장 컴포넌트가 포함되어 있지만, 애니메이션 차트, 사용자 정의 스위치, 자유 그리기 캔버스, 게임 요소 또는 데이터 시각화와 같은 모든 시나리오를 다루지는 않으므로 사용자 정의 구현이 필요합니다.

Apple은 표준 컴포넌트가 필요한 기능을 제공할 수 없거나 동일한 사용자 정의 요소가 애플리케이션의 여러 곳에서 사용될 때 Custom UIView 생성을 권장합니다. WWDC 2024에 따르면, 중간 규모 프로젝트에서 사용자 정의 뷰는 전체 UIView의 평균 15-20%를 차지합니다.

일반적인 사용 사례

Custom UIView는 차트 및 다이어그램 구축(Core Graphics로 선과 도형 그리기), 사용자 정의 진행 표시기, 애니메이션 배경, 손가락 그리기 요소 및 실시간 데이터 시각화에 사용됩니다. 각각의 경우에서 개발자는 CGContext에 대한 완전한 액세스 권한을 얻고 모든 지오메트리를 그릴 수 있습니다.

Custom UIView가 필요하지 않은 경우

요소를 표준 UIKit 컴포넌트(UIButton, UIImageView, UILabel)와 Auto Layout 및 속성 설정을 사용하여 조립할 수 있다면 UIView 서브클래스를 만드는 것은 과도합니다. Apple은 먼저 기성 뷰의 구성을 시도하고 기능이 충분하지 않을 때만 사용자 정의 드로잉으로 전환할 것을 권장합니다.

Xcode에서 Custom UIView 생성 방법

사용자 정의 UIView 생성은 UIView에서 상속받는 클래스 선언과 필수 초기화 메서드 구현으로 시작됩니다. 최소 구현에는 코드에서 생성을 위한 init(frame:)과 Storyboard 또는 XIB에서 로드를 위한 init(coder:)가 포함됩니다.

swift
import UIKit

class CircleView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }

    private func setupView() {
        backgroundColor = .clear
        setupLayerProperties()
    }

    private func setupLayerProperties() {
        layer.cornerRadius = bounds.width / 2
        layer.masksToBounds = true
    }
}

setupView() 메서드에서 투명 배경, 레이어 설정 등의 초기 속성이 설정됩니다. 뷰가 Interface Builder에 표시되는 경우 라이브 미리보기를 위해 @IBDesignable@IBInspectable을 추가하는 것이 좋습니다.

UIView 생명주기 메서드

Custom UIView는 특정 순서로 호출되는 일련의 생명주기 메서드를 통해 시스템에 의해 관리됩니다. 이 주기를 이해하는 것은 뷰의 올바른 설정 및 드로잉에 매우 중요합니다.

메서드호출 시점목적
init(frame:)코드에서 뷰 생성속성 초기화, 하위 뷰 추가
init(coder:)Storyboard/XIB에서 로드역직렬화 및 초기 설정
layoutSubviews()프레임 변경 시하위 요소 지오메트리 재계산
draw(_:)첫 표시 시 또는 setNeedsDisplay() 후Core Graphics를 통한 콘텐츠 드로잉
didMoveToSuperview()계층 구조에 추가된 후최종 설정, 애니메이션 시작

모든 메서드는 시스템에 의해 자동으로 호출되며, 개발자가 직접 호출할 필요가 없습니다. 예외는 setNeedsDisplay()로, 시스템에 draw(_:)를 다시 호출해야 함을 알립니다.

드로잉을 위한 draw(_:) 재정의

draw(_:)는 Custom UIView에서 사용자 정의 드로잉을 위한 핵심 메서드입니다. 이 메서드 내에서 개발자는 CGContext(그래픽 컨텍스트)에 액세스하여 Core Graphics를 사용해 선, 도형, 텍스트 및 이미지를 그릴 수 있습니다.

시스템은 뷰가 화면에 처음 나타날 때 자동으로 draw(_:)를 호출합니다. 이후 호출은 뷰를 다시 그려야 함을 표시하는 setNeedsDisplay()에 의해 트리거됩니다. 중요: draw(_:)를 직접 호출하지 마세요. 캐싱 메커니즘이 손상되고 성능이 저하됩니다.

swift
override func draw(_ rect: CGRect) {
    guard let context = UIGraphicsGetCurrentContext() else { return }

    // 배경 채우기
    context.setFillColor(UIColor.systemBlue.cgColor)
    context.fill(rect)

    // 원 그리기
    context.setStrokeColor(UIColor.white.cgColor)
    context.setLineWidth(4.0)
    let circleRect = rect.insetBy(dx: 20, dy: 20)
    context.strokeEllipse(in: circleRect)
}

이 예제에서 draw(_:)는 배경을 파란색으로 채우고 가장자리에서 20픽셀 간격으로 흰색 원을 그립니다. draw(_:)의 각 호출은 멱등적이어야 합니다. 동일한 매개변수로 여러 번 호출해도 동일한 결과를 생성해야 합니다.

효과적인 draw(_:) 규칙

Apple은 draw(_:) 내에서 작업을 최소화할 것을 권장합니다. UIBezierPath를 미리 생성하고, 이미지를 캐싱하며, 무거운 계산을 수행하지 마세요. 뷰가 정적인 경우 지속적인 다시 그리기 대신 렌더링된 이미지와 함께 UIImageView 사용을 고려하세요.

CALayer vs draw(_:): 선택 가이드

CALayer는 UIView의 시각적 콘텐츠를 관리하는 기본 레이어입니다. 많은 사용자 정의 드로잉 작업은 draw(_:)를 재정의하지 않고 CALayer 속성을 구성하여 해결할 수 있으며, 이는 훨씬 더 효율적입니다.

Apple Engineering(2024)에 따르면, CALayer 수준의 작업은 GPU에서 실행되는 반면, draw(_:)는 CPU 기반 Core Graphics 렌더링을 통해 작동합니다. 애니메이션 및 부드러운 전환을 위해서는 CALayer 및 CABasicAnimation을 사용하는 것이 좋습니다.

시나리오권장 접근 방식성능
둥근 모서리layer.cornerRadiusGPU, 높음
그림자 및 그라데이션CAGradientLayer, shadowPathGPU, 높음
임의의 도형UIBezierPath를 사용한 CAShapeLayerGPU, 높음
복잡한 그래픽Core Graphics를 사용한 draw(_:)CPU, 중간
사용자 정의 서식의 텍스트CATextLayer 또는 draw(_:)볼륨에 따라 다름

애니메이션이 있는 벡터 도형을 그리려면 CAShapeLayer를 사용하세요. 하드웨어 가속이 지원되며 draw(_:)를 호출하지 않고 path, strokeStart 및 strokeEnd 애니메이션을 지원합니다.

Custom UIView 성능 최적화

Custom UIView의 성능은 애니메이션의 부드러움과 전반적인 사용자 경험에 직접적인 영향을 미칩니다. 주요 문제는 과도한 draw(_:) 호출, 최적이 아닌 하위 뷰 레이아웃 및 캐싱 부족에서 발생합니다.

불필요한 다시 그리기 방지

setNeedsDisplay()를 호출할 때마다 뷰가 완전히 다시 그려집니다. 변경 사항이 뷰의 일부에만 영향을 미치는 경우 특정 사각형과 함께 setNeedsDisplay(_:)를 사용하세요. CALayer 속성(backgroundColor, cornerRadius, shadow)의 경우 다시 그리기가 필요하지 않습니다. GPU 수준에서 업데이트됩니다.

렌더링된 콘텐츠 캐싱

Custom UIView의 콘텐츠가 자주 변경되지 않는 경우 UIGraphicsImageRenderer에서 한 번 렌더링하고 UIImage로 저장하세요. 다음 다시 그리기 시 캐시된 이미지를 표시하려면 draw(at:)를 사용하세요. Core Graphics를 통한 재렌더링보다 수십 배 빠릅니다.

swift
func renderToImage() -> UIImage {
    let renderer = UIGraphicsImageRenderer(size: bounds.size)
    return renderer.image { ctx in
        drawHierarchy(in: bounds, afterScreenUpdates: true)
    }
}

정적 레이어에는 shouldRasterize 사용

CALayer의 shouldRasterize 속성은 레이어의 비트맵 표현 캐싱을 활성화합니다. 투명도와 그림자가 있는 정적 뷰에서 이 기능을 활성화하면 합성 부하가 줄어듭니다. 애니메이션 뷰에서는 비활성화하세요. 변경 시마다 캐시가 재설정되며, 래스터화는 성능을 저하시킬 뿐입니다.

자주 묻는 질문

Custom UIView에서 draw(_:)를 재정의해야 하나요?

아니요. draw(_:)는 Core Graphics를 통한 사용자 정의 드로잉에만 필요합니다. 뷰가 표준 하위 뷰(UILabel, UIImageView)로 구성되고 CALayer를 사용하는 경우 draw(_:)를 재정의할 필요가 없습니다. 성능이 향상될 수도 있습니다.

Storyboard에 Custom UIView를 추가하는 방법은?

캔버스에 일반 UIView를 배치하고 Identity Inspector의 Class 필드에 클래스를 지정합니다. 클래스가 @IBDesignable로 표시된 경우 변경 사항이 Storyboard에 실시간으로 표시됩니다.

init(frame:)과 init(coder:)의 차이점은?

init(frame:)은 프로그래밍 방식으로 뷰를 생성할 때 호출되며 위치와 크기가 있는 CGRect를 전달합니다. init(coder:)는 Storyboard 또는 XIB에서 역직렬화할 때 호출됩니다. 올바른 작동을 위해 둘 다 구현해야 합니다. 그렇지 않으면 Interface Builder에서 로드할 때 뷰가 충돌합니다.

draw(_:)가 호출되지 않는 이유는?

가장 일반적인 이유는 뷰에 프레임이 0(너비 또는 높이가 0)이기 때문입니다. 시스템은 0 크기의 뷰에 대해 draw(_:)를 호출하지 않습니다. layoutSubviews()에서 프레임을 확인하고 뷰가 올바른 제약 조건으로 계층 구조에 추가되었는지 확인하세요.

전체 다시 그리기 없이 Custom UIView 콘텐츠를 업데이트하려면?

GPU 애니메이션(position, opacity, transform)을 지원하는 속성에는 CALayer를 사용하세요. draw(_:)의 부분 업데이트의 경우 변경된 영역의 CGRect와 함께 setNeedsDisplay(_:)를 사용하세요. 시스템은 전체 뷰가 아닌 지정된 영역만 다시 그립니다.

요약

  • Custom UIView — 표준 UIKit 컴포넌트가 부족할 때 사용되는, 사용자 정의 드로잉을 위해 메서드를 재정의한 UIView 서브클래스
  • draw(_:) — Core Graphics를 통한 사용자 정의 드로잉 메서드, 시스템에 의해 자동 호출됨; 직접 호출 금지
  • CALayer — GPU 가속 그래픽(그림자, 둥글기, 도형)을 위한 권장 접근 방식, draw(_:)의 대안으로 높은 성능 제공
  • init(frame:)init(coder:) — 필수 초기화 메서드; 코드와 Storyboard에서 올바르게 작동하려면 둘 다 구현해야 함
  • setNeedsDisplay() — 시스템에 draw(_:) 재호출을 알림; 부분 다시 그리기를 위해 CGRect 오버로드 사용
  • @IBDesignable — Interface Builder에서 Custom UIView의 라이브 미리보기를 위한 속성, 시각적 개발 간소화
  • 정적 그래픽의 경우 UIGraphicsImageRenderer를 통해 결과를 캐시하고 준비된 이미지를 그리면 CPU 부하가 줄어듭니다

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기