해당 글은 Apple 공식문서를 번역한 글로 의역이나 잘못 번역된 내용이 있을 수 있습니다.
정확한 내용은 원문을 참고해주세요.
https://developer.apple.com/documentation/swiftui/declaring-a-custom-view#Conform-to-the-view-protocol
개요
SwiftUI는 사용자 인터페이스 디자인을 선언형(declarative) 방식으로 제공합니다.
전통적인 명령형(imperative) 방식에서는 뷰를 생성하고, 배치하고, 설정하는 책임은 물론, 상태 변화에 따라 뷰를 지속적으로 업데이트하는 책임까지 컨트롤러 코드가 부담합니다.
반면, 선언형 방식에서는 UI의 원하는 레이아웃을 반영하는 뷰 계층을 선언함으로써, 사용자 인터페이스의 *간단한 설명(lightweight description)을 만듭니다. 그 이후에는 SwiftUI가 사용자 입력이나 상태 변화 같은 이벤트에 반응하여 뷰를 그리거나 업데이트하는 과정을 관리합니다.
SwiftUI는 사용자 인터페이스 내에서 뷰를 정의하고 구성하기 위한 도구를 제공합니다. SwiftUI가 제공하는 내장 뷰들과 이미 정의된 다른 컴포지트 뷰들을 조합하여 커스텀 뷰를 만들 수 있습니다. 뷰는 수정자(modifier)를 통해 설정하고, 데이터 모델과 연결할 수 있습니다. 이후 이러한 커스텀 뷰를 앱의 뷰 계층 안에 배치할 수 있습니다.
View 프로토콜을 따르기
커스텀 뷰 타입을 선언하려면, View 프로토콜을 따르는 구조체를 정의해야 합니다:
struct MyView: View {
}
Swift의 다른 프로토콜들과 마찬가지로, View 프로토콜은 특정 기능의 설계도를 제공합니다.
여기서는 SwiftUI가 화면에 그리는 요소의 동작을 정의합니다. 프로토콜을 따르기 위해 필요한 요구사항을 충족하고 나면, 커스텀 뷰를 뷰 계층에 삽입하여 앱의 사용자 인터페이스 일부로 만들 수 있습니다
body 선언하기
View 프로토콜의 주요 요구사항은 body라는 계산 프로퍼티(computed property)를 정의하는 것입니다:
struct MyView: View {
var body: some View {
}
}
SwiftUI는 뷰를 업데이트할 필요가 있을 때마다 이 프로퍼티의 값을 읽습니다. 이러한 업데이트는 사용자 입력이나 시스템 이벤트에 반응하여 반복적으로 일어날 수 있습니다. 이때 반환된 값은 SwiftUI가 화면에 그리는 요소입니다.
View 프로토콜의 부가적인 요구사항은 body 프로퍼티에 대한 연관 타입(associated type)을 지정해야 한다는 것입니다. 하지만 이 타입을 명시적으로 선언할 필요는 없습니다. 대신 some View라는 불투명 타입(opaque type)을 사용하여 body의 반환값이 View 프로토콜을 따른다는 사실만 명시합니다. 정확한 타입은 body의 내용에 따라 달라지며, Swift가 이를 자동으로 추론합니다.
뷰 콘텐츠 구성하기
body 프로퍼티에 콘텐츠를 추가하여 뷰의 외형을 설명합니다. SwiftUI에서 제공하는 내장 뷰는 물론, 다른 곳에서 정의한 커스텀 뷰도 사용할 수 있습니다. 예를 들어, 내장 Text 뷰를 사용하여 “Hello, World!“라는 문자열을 표시할 수 있습니다:
struct MyView: View {
var body: some View {
Text("Hello, World!")
}
}
SwiftUI는 Text, Toggle, ProgressView와 같은 특정 콘텐츠를 위한 뷰 외에도, 다른 뷰들을 정렬하는 데 사용할 수 있는 내장 뷰들을 제공합니다. 예를 들어 VStack을 사용해 두 개의 Text 뷰를 수직으로 쌓을 수 있습니다:
struct MyView: View {
var body: some View {
VStack {
Text("Hello, World!")
Text("Glad to meet you.")
}
}
}
위 예시처럼 여러 자식 뷰를 입력받는 뷰는 일반적으로 ViewBuilder 속성으로 표시된 클로저를 통해 구성됩니다.
*이 덕분에 호출하는 쪽에서는 특별한 문법 없이 여러 줄로 된 클로저를 사용할 수 있으며, 뷰들을 차례대로 나열하기만 하면 됩니다.(This enables a multiple-statement closure that doesn’t require additional syntax at the call site. You only need to list the input views in succession.)
다른 뷰를 포함하는 뷰에 대한 더 많은 예시는 레이아웃 기초를 참고하세요.
뷰를 수정자로 구성하기
body에 정의된 뷰를 설정하려면 뷰 수정자(view modifier)를 적용합니다. 수정자는 뷰에 호출되는 메서드일 뿐이며, *호출 시 원래 뷰 대신 사용할 수 있는 새로운 뷰를 반환합니다.(The method returns a new, altered view that effectively takes the place of the original in the view hierarchy.)
SwiftUI는 이를 위해 View 프로토콜에 다양한 메서드를 확장으로 제공합니다. 모든 View 프로토콜 채택자는 — 내장 뷰든 커스텀 뷰든 — 이러한 메서드를 통해 뷰의 동작을 변경할 수 있습니다. 예를 들어, 텍스트 뷰의 폰트를 .title로 설정하려면 다음과 같이 작성합니다:
struct MyView: View {
var body: some View {
VStack {
Text("Hello, World!")
.font(.title)
Text("Glad to meet you.")
}
}
}
뷰 수정자의 작동 방식 및 사용법에 대한 자세한 내용은 Configuring views를 참고하세요.
데이터 관리하기
뷰에 값을 전달하려면 속성(property)을 추가하세요. 예를 들어, “Hello, World!” 문자열의 폰트를 설정 가능하도록 할 수 있습니다:
struct MyView: View {
let helloFont: Font
var body: some View {
VStack {
Text("Hello, World!")
.font(helloFont)
Text("Glad to meet you.")
}
}
}
입력값이 변경되면 SwiftUI는 해당 변경 사항을 감지하고, 사용자 인터페이스의 영향을 받는 부분만 다시 그립니다. 이는 뷰 전체를 재초기화하는 작업을 포함할 수 있지만, SwiftUI가 이를 자동으로 관리합니다.
SwiftUI는 언제든지 뷰를 재초기화할 수 있으므로, 뷰의 초기화 코드에서 큰 작업을 수행하는 것은 지양해야 합니다. 위 예시처럼 초기화 코드를 명시적으로 작성하지 않고 Swift가 자동 생성하는 member-wise initializer를 사용하는 것이 좋습니다.
SwiftUI는 이러한 제약 안에서 앱의 데이터를 관리할 수 있는 다양한 도구를 제공합니다. 자세한 내용은 Model data를 참고하고, Swift 초기화에 대한 정보는 The Swift Programming Language - Initialization을 참고하세요.
뷰 계층에 추가하기
뷰를 정의한 후에는, 내장 뷰와 마찬가지로 다른 뷰 안에 포함시킬 수 있습니다. 뷰를 어디에 나타내고 싶은지에 따라 해당 위치에 선언하면 됩니다.
예를 들어, Xcode가 새로운 앱 프로젝트에서 루트 뷰로 생성하는 ContentView 안에 MyView를 넣을 수 있습니다
struct ContentView: View {
var body: some View {
MyView(helloFont: .title)
}
}
또는 새로운 장면(scene)의 루트 뷰로 사용할 수도 있습니다. 예를 들어 macOS 환경에서 설정 창을 위한 Settings scene이나, watchOS에서 알림 화면을 위한 WKNotificationScene 등에서 사용될 수 있습니다.
SwiftUI로 앱의 구조를 정의하는 방법에 대한 자세한 정보는 App organization을 참고하세요.
'iOS' 카테고리의 다른 글
Demystify SwiftUI - Identify: SwiftUI는 뷰를 어떻게 구분할까? (0) | 2025.06.09 |
---|---|
번역) SwiftUI 간단한 뷰 레이아웃 구성하기 (2) | 2025.06.06 |
애플 로그인 서버부터 클라이언트까지(Swift + Nest.js + TypeScript) (1) | 2025.05.22 |
CoreData 개요 및 동시성 (0) | 2025.05.21 |
Alamofire 기능 정리 (0) | 2025.05.12 |