안녕하세요, iOS 개발하는 루피입니다.
오늘은 WWDC21 Demystify SwiftUI 영상을 보고 정리해보는 시간은 갖으려 합니다. 이번 영상은 선언형 프레임워크인 SwiftUI가 내부적으로 무엇을 하고 있는지에 대해 설명하면서, “SwiftUI가 내 코드를 볼 때, 무엇을 보는가?”라는 주제를 바탕으로 정보를 전달하는데요, 이번 글은 정리를 목적으로 진행하며, 총 3개의 글로 정리해보겠습니다. 바로 시작합니다.
SwiftUI가 집중하는 3가지
- Identity : SwiftUI가 여러 업데이트에서 요소를 동일하거나 별개로 인식하는 방식이다.
- Lifetime : SwiftUI가 시간 경과에 따라 뷰와 데이터의 존재를 추적하는 방식이다.
- Dependencies : SwiftUI가 인터페이스를 업데이트해야 하는 시점과 그 이유를 이해하는 방식이다.
이 3가지 개념은 SwiftUI가 무엇을, 어떻게, 언제 변경해야 하는지 결정하는 방식에 영향을 미치며, 그 결과 화면에 표시되는 동적인 UI가 만들어지게 된다.
이번 영상을 보는데 가장 핵심이 되는 3가지 개념입니다. 오늘은 Identity 부분을 정리해보겠습니다.
Identity
아래의 앱은 화면을 탭 하면 착한 상태와 나쁜 상태 아이콘이 바뀝니다. 그러면 여기에 질문을 하나 던져 보겠습니다. 아래의 두 화면은 아이콘이 완전히 다른 뷰일까요, 아니면 같은 뷰가 다른 위치와 색으로 표현된 걸까요?

이 두 가지 방식을 구분하는 것은 중요합니다. 왜냐하면, 그 차이에 따라 상태가 전환되는 방식이 달라지기 때문입니다. 즉 UI의 트랜지션 방식이 달라지게 하는데요.
만약 다른 뷰라면, 별개로 페이드인/아웃 같이 독립적으로 전환되어야 하고, 같은 뷰라면 위치를 옮기며, 슬라이드로 트랜지션 해야 합니다. 이처럼 SwiftUI는 같은 Identity를 공유하면, 같은 UI 요소의 상태 변화, 다른 Identity라면 별개의 요소로 이해합니다.
SwiftUI의 2가지 Idntity
SwiftUI에서는 두 개의 Identity 개념을 바탕으로 View의 정체성을 판단합니다.
1. Explicit identity (명시적 아이덴티티)
명시적 Identity는 사용자 정의 또는 데이터 기반 식별자를 사용합니다. 예시를 들어보겠습니다.
우리는 주변에서 일란성쌍둥이를 볼 수 있는데요, 두 쌍둥이의 외관이 정확히 같다는 가정을 하고 우리는 이 둘의 사진을 보고 누가 누구인지 구별할 수 있을까요? 많이 힘들겠죠 ㅎㅎ. 그렇다면 이때 그 사진 하단에 찍힌 사람의 이름을 적는다면 어떨까요? 구분하기 훨씬 쉬어질 겁니다. 이렇게 이름이나 식별자를 지정하는 것이 명시적 Identity입니다. 하지만, 이러한 방식은 누군가가 어딘가에서 모든 이름을 추적해야 합니다.
UIkit / AppKit의 방식
우리가 흔히 알 수 있는 명시적 Identity의 형태는 UIKit과 AppKit 전체에서 사용되는 포인터 ID가 있습니다.

우리가 UIKit과 AppKit으로 개발하면서 자주 사용하는 UIView와 NSView는 클래스인데요, 각각 메모리 할당에 대한 고유한 포인터를 갖고 있게 됩니다. 그렇기에 우리는 포인터를 바탕으로 명확하게 정체성을 확인할 수 있고, 만약에 두 View가 같은 포인터를 공유하는 경우 두 View는 동일한 뷰라는 것을 보장할 수 있게 됩니다.
SwiftUI의 방식
하지만 SwiftUI에서 View는 일반적으로 클래스 대신 구조체로 표현되는 값 유형입니다. 그렇기에 뷰의 영구적인 ID로 사용할 수 있는 정식적인 참조가 없다는 것을 의미하기도 합니다.(SwiftUI essentials WWDC 2019)

그렇다면 SwiftUI는 어떻게 명시적 ID를 부여할까요? 여기에는 SwiftUI가 사용하는 다른 형태의 명시적 ID가 존재합니다.
List {
Section {
ForEach(rescueDogs, id: \.dogTagID) { rescueDog in
ProfileView(rescueDog)
}
}
Section("Status") {
ForEach(adoptedDogs, id: \.dogTagID) { rescueDog in
ProfileView(rescueDog, foundForeverHome: true)
}
}
}
여기에 사용된 id 매개변수는 명시적 ID의 한 형태입니다. id를 바탕으로 해당 뷰를 명확하게 식별하게 되는데요. 이를 바탕으로 컬렉션이 바뀌어도 SwiftUI는 id 값 덕분에 정밀하게 변경점을 파악하고 애니메이션도 올바르게 처리합니다.
ScrollViewReader { proxy in
ScrollView {
HeaderView(rescueDog)
.id(headerID)
Text(rescueDog.backstory)
Button("Jump to Top") {
withAnimation {
proxy.scrollTo(headerID)
}
}
}
}
위 같은 기능도 만들 수 있는데요. 제일 하단에 있는 버튼을 클릭하면 바로 Header, 즉 가장 상단으로 이동할 수 있습니다.
이러한 방식의 장점은 오직, 다른 코드(ScrollViewReader, ForEach 등)에서 특정 뷰에 "직접 접근하거나 조작"해야 할 때만 명시적 id로 뷰를 식별하면 되도록 만들 수 있다는 것입니다.
그러면 의문의 생길 거 같은데요.. “다른 View는 그럼 아이덴티티를 갖지 않는 건가?”
아닙니다. 나머지 대부분의 뷰는 SwiftUI가 구조적 아이덴티티만으로 알아서 관리하게 됩니다.
2. Structural identity (구조적 아이덴티티)
뷰 계층 구조에서 뷰의 유형과 위치를 기준으로 뷰를 구분합니다. 즉 아래와 같이 “왼쪽에 있는 개” 와 “오른쪽에 있는 개”처럼 위치만으로 식별을 가능하게 한다는 것입니다.

아래 코드를 바탕으로 설명을 이어나가도록 하겠습니다.

가장 흔한 패턴 중 하나인 if문을 사용해서 true/false에 따라 각각 다른 View를 보여주는 로직입니다.
SwiftUI는 이러한 조건에 따른 분기를 해석할 때, 각 분기마다 실제로 서로 다른 View를 만듭니다. 즉, 조건에 따라 각각 별도의 View 타입이 생성되는 것이죠. (if문이 _ConditionalContent View로 변환됩니다.)
이 구조는 Swift의 ViewBuilder 결과 생성 방식을 기반으로 작동됩니다.
결국, true View가 항상 AdoptionDirectory이고, False View가 항상 DogList임을 보장하면서, 내부적으로 암묵적이고 안정적인 ID를 할당할 수 있게 해 줍니다. 그리고 이러한 개념이 지금까지의 내용을 이해하는 Key입니다.
3. Identity에 따른 차이
SwiftUI는 if 문의 각 분기가 고유한 정체성을 가진 다른 뷰를 나타낸다는 것을 이해하기 때문에 아래의 뷰는 서로 다른 뷰를 나타낸다는 것으로 이해하고 SwiftUI는 슬라이드로 View를 트랜지션 하게 됩니다.
VStack {
if dog.isGood {
PawView(tint: .green)
Spacer()
} else {
Spacer()
PawView(tint: .red)
}
}
물론 아래와 같이 같은 아이덴티티를 유지하면서 속성만 다르게 변경하는 방식 역시 가능합니다.
Paw(tint: dog.isGood ? .green : .red)
.frame {
maxHeight: .infinity,
alignment: dog.isGood ? .top : .bottom)
동작 방식의 차이
아래의 두 영상은 View에 정체성 판단에 따른 다른 결과를 보여줍니다. 그리고 SwiftUI는 2번째 방식인 정체성을 유지하는 방식을 권장합니다. 그에 대한 이유로 View의 생명주기와 상태를 보존을 위해서라고 합니다.
REF
WWDC21: Demystify SwiftUI | Apple
해당 내용 이후 “AnyView를 사용하지 말자” 라는 주제로 영상에 내용이 추가되어 있지만, 해당 내용은 따로 정리할 예정입니다. 오늘도 화이팅입니다.
'iOS > SwiftUI' 카테고리의 다른 글
| [SwiftUI] Demystify SwiftUI (3/3) - Dependencies (0) | 2025.10.30 |
|---|---|
| [SwiftUI] Demystify SwiftUI (2/3) - Lifetime (0) | 2025.10.29 |
| [SwiftUI] some View (0) | 2025.05.15 |
| [SwiftUI] View & Modifiers (0) | 2025.05.13 |
| [SwiftUI] StateObject (0) | 2025.04.21 |