[WWDC2021] Demystify SwiftUI
SwiftUI의 선언형 UI
- 뷰를 그리면서, 어떤 목적을 달성하고자 하는지 설명하면 프레임워크가 해결해 줄 수 있다.
- 그런데 어떤 일이 일어나고 있나?
Identity, lifetime, Dependenceis
- 뷰가 어떤 이유로 어떻게 그려지는지, 얼마나 데이터를 갖고 뷰가 유지되어야 하는지, 그리고 그 뷰의 id는 무엇인지를 기준으로 알아보고자 한다.
Identity
- 두 강아지가.. 다르다면? 어떻게 다른가? 그 동일성은 어디서 오는가?
- SwiftUI가 동일성을 통해 뷰를 구분하기 때문에 이 물음은 중요하다. 어떻게 동일성을 갖게 할 것인가?
- 두 뷰의 컴포넌트가 다르다고 가정하다면, fade in-out으로 그릴 수 있고, 같다면 trasition으로 뷰가 옮겨다닐 수 있음을 의미한다.
- ID를 갖고 명시적인 identity를 가질지, 아니면 구조에 따른 identity를 가질지는 차이가 있을 수 있다.
- 메모리 주소로 id를 갖게 하는 pointer ID 방식은 SwiftUi가 선호하지 않는다.
- 구조체로서의 뷰는 값 타입으로서 작용하기 때문에 모든 뷰는 copy 된다는 점도 한몫하고,
.id
수식어로 id를 명시적으로 줄 수 있다.
- 반면 구조적 identity는 어떠한가?
- 조건문에 따라 서로 다른 뷰가 나뉠 때, true View, false View라는 구별이 가능하다.
- 뷰의 제네릭 타입을 보기 때문에 이러한 구별은 강하게 보장된다.
- SwiftUI는 더 유연한 변화를 지향하기 때문에 구조적 Identity 구별을 더욱 장려한다.
AnyView(type easing wrapper type)
- 그런데 만약
AnyView
를 쓰면 어떻게 될까?
- 구조적 동일성이
AnyView
라는 제너릭 타입으로 단일화되기 때문에 리턴되는 제너릭 타입에 대응하는 some View
가 서로 다른 뷰로 구별되지 않는다.
- 보자마자 굉장히 이해하기 어려운 코드가 되는 동시에, 동일성을 해치고 퍼포먼스도 낮추기 때문에
AnyView
의 사용은 지양하는 것이 좋다.
AnyView
를 쓰기보다는 if
, 삼항연산, switch
등으로 대치하여 쓰도록 하자.
Lifetime
- 언제까지 뷰는 살아있는가? 동일성을 가진 뷰가 시간에 의해 데이터에 남아있는 것을 수명이라 한다.
- 같은 뷰에서 State의 변화로 인해 뷰가 새로 그려진다면, 이전 값을 갖고 있던 뷰는 사라진다.
- 즉
View Value
와 View Identity
는 서로 다르다.
- 뷰의 수명은 화면에서 보이는지의 여부에 따라 결정된다(onAppear ~ onDisappear)
- 뷰의 id에 연관되는 내부의 State와 StateObject는 그 값이 바뀔 때마다 뷰를 새로 그린다.
- 서로 다른 동일성을 갖는 뷰가 조건에 의해 분기처리 된다면, 조건에 의해 뷰가 바뀔 때마다 뷰의 데이터는 말소되고 새로 초기화된다.
- 따라서 State의 수명은 View의 수명과 동일하게 유지된다.
- 동일성을 유지해야 각 뷰가 갖는 State가 안정적임을 보장할 수 있기 때문에, List, ForEach에 다이나믹한 콜렉션을 돌리고 싶다면
Identifiable
, Hashable
프로토콜을 넣어주도록 하자(애초에 정의할 때부터 Content
제너릭 타입이 Identifiable
을 채택할 것을 요구하긴 하지만).
- 뷰 빌더는 모두 Data Driven 하다는 점을 함께 기억하자.
- 뷰의 수명은 그것의 id가 유지되는 기간을 의미하며, state의 일관성은 수명에 종속된다.
Dependency
- 의존성은 뷰의
input
에 불과하다.
- SwiftUI의 뷰 컴포넌트가 갖는
action
들은 뷰의 의존성을 변경시키는 행동을 할 수 있고, 이는 뷰를 다시 계산하도록 한다.
- 뷰의 계층에 따라 뷰에 어떤 데이터가 종속되어서 변화를 촉구하는지 달라질 수 있다.
- 사진의 맨 아래의 state는 자신의 변화에 따라 2개의 뷰를 바꾸도록 한다.
- 그런데 만약 이 변화된 뷰의 하위 뷰가 수명주기에서 내려가 있다면 굳이 그 뷰가 다시 그려지지는 않을 것이다.
Identifier Stability & Uniqueness
- 수명에 직결되며 성능 향상에 도움이 될 수 있다.
- minimizes dependency churn
UUID().uuidstring
같은 random generated id는 뷰에 의해 생성될 때마다 바뀌기 때문에 stable하지 않다.
- id는 따라서 유니크해야 하는데 이 역시 성능 향상과 직관적 애니메이션에 도움을 준다.
- 그런데 구조적 동일성에 의해 if 조건에 따라 브랜치가 나뉠 수 있다. 이러면 동일한 id를 가진 2개의 뷰가 생길 수 있고 애니메이션을 저하하거나 state의 안정성을 해칠 수 있다. 이럴 땐 삼항연산자(
Dependent Code
)를 써보자.