목차
1. Identifiable 프로토콜을 통한 데이터 뿌리기
2. SwiftUI의 뷰 업데이트 방식
3. SwiftUI의 상태관리
(주의: WWDC에서 소개된 내용 중 중요하지 않다고 판단된 내용은 제외시켰음)
Identifiable 프로토콜을 통한 데이터 뿌리기
SwiftUI는 껍데기 UI들을 컴포지셔닝으로 만든 뒤 상위에서 Source Of Truth 를 관리하면서 하위 뷰들에게 데이터를 뿌리는 형태이다. List(UIKit에서의 테이블뷰와 컬렉션뷰 대체)를 예로 들자면 테이블뷰와 각 셀의 내용물은 하나의 셀 껍데기만 만들어 반복으로 돌리면 된다. 여기서 사진, 텍스트의 모양, 위치, 색과 같은 껍데기는 같다. 이제 문제는 어떻게 각 셀마다 다른 내용물을 뿌려줄 것인가이다.
생각해보면 모델은 똑같다. 사진-Room타이틀-사람인원수 등이다. 다만 다른 내용물이 채워질 뿐이다. SwiftUI의 List는 같은 타입(모델)이지만 서로다른 내용물을 구분해서 뿌려주어야한다. 따라서 각 인스턴스가 같은 타입이어도 구분할 수 있는 증거가 필요하다. 이러한 구분된 인스턴스를 찍어낼 것이라고 보장해주는 증표가 바로 Identifiable Protocol 이다.
당연한 이야기이지만 각 인스턴스를 구분하는 방법으로 꼭 UUID를 사용할 필요는 없다. 구분 가능한 프로퍼티 하나만 가지면 Identifiable Protocol 을 채택할 수 있다. 이때 구분가능한 프로퍼티는 Hashable 타입을 채택하고 있기만 하면 된다. 그렇다면 왜 Hashable 프로토콜을 채택한 타입의 인스턴스는 구분이 가능할까? Hashable 타입은 이미 Equatable 타입을 채택하고 있기때문이다.
이를 통해 Hashable 타입을 채택한 인스턴스는 객체를 고유한 정수로 나타낸뒤 구분할 수 있다. 이 과정을 아래 한 문장으로 요약할 수 있다.
Equatable (동등성 비교가능) -> Hashable(객체를 해시값으로 변환 가능) -> Identifiable (고유한 식별자를 통해 구분 가능)
Identifiable 프로토콜을 채택한 Room 타입 배열을 List에 넣어 같은 UI 껍데기에 구분된 내용물들을 채워줄 수 있다.
SwiftUI의 View 업데이트 방식
View Protocol은 단 하나의 내용물로 구성되어 있다. 바로 body이다. 하지만 이 바디도 결국 View 타입의 typeAlias이기 때문에 View를 가지고 있다 볼 수 있다. SwiftUI에서 View를 렌더링한다는 것은 body를 렌더링한다는 것과 같다. 또한 뷰는 기본적으로 값타입이기 때문에 바뀌는 값을 참조하지 않고 값이 바뀌면 그냥 새로 한 번더 그려주어야한다. 그렇다면 View는 body의 변화를 어떻게 알아채고 업데이트할까?
초록색은 개발자가 관리하는 메모리이고 보라색은 SwiftUI가 관리하는 메모리 영역이다. UI껍데기가 참조하고 있는 데이터를 @State 프로퍼티 래퍼를 통해 스유가 바인딩을 관리해준다. 이렇게 SwiftUI 프레임워크가 데이터 변화 감지를 도맡아 하면서 오른쪽 사진과 같이 뷰가 데이터 변화 감지에 실패하는 일은 거의 일어나지 않게된다.
사진을 보면 서로 다른 UI 세 개의 껍데기에 하나의 데이터 모델 배열이 들어가서 데이터가 각 뷰에 뿌려지고 있다는 것을 확인할 수 있다. SwiftUI 에서 사용되는 데이터는 크게 두 가지 종류로 나눌 수 있다. 바로 Source Of Truth와 Derived Value 이다.
코드를 통해 보면 room이 SourceOfTruth 로 데이터의 원천이라 볼 수 있고 각기 뿌려지는 데이터가 Derived Value라고 볼 수 있다.
이러한 두 종류의데이터는 읽기 전용으로 둘 것인가와 읽기/쓰기 작업을 할 것이냐에 따라 다르게 선언한다.
만약 읽기 작업만 한다면 단순히 상수선언을 해서 데이터를 주입시켜주면 된다. 하지만 이렇게 되면 View는 처음 생성될 때 데이터만 읽고 그 이후의 데이터 변화는 알아채기 힘들어진다. 만약 쓰기 작업이 들어가고 데이터 업데이트를 감지해서 뷰를 업데이트해야한다면 Source Of Truth 에는 @State 프로퍼티 래퍼를 붙이고 Derived Value에서는 @Binding 프로퍼티 래퍼를 붙여주어야만 한다.
SwiftUI의 상태관리
왜 애플은 Source Of Truth 라는 아이디어를 가져왔을까?
결국 우리가 하는 일은 UI껍데기에 데이터를 뿌리고 데이터가 업데이트 되면 UI를 다시 렌더링하는 것이다.
따라서 View는 암묵적으로 Data에 대한 의존성이 생긴다. 개발자를 힘들게 하는 것은 가변하는 데이터 상태에 대한 의존성 관리이다.
왜 상태관리가 iOS개발에 있어서 중요한가는 위 예제를 통해 살펴볼 수 있다.
만약 하나의 뷰에서 4가지 상태를 가지고 있다고 해보자. 이러한 4가지 상태가 나타낼 수 있는 뷰의 상태는 4 x 3 x 2 x 1 로 24가지 뷰를 표현할 수 있다.
더불어 상태가 네트워크나 DB같은 I/O작업으로 들어오거나 바뀌면 비동기로 처리되어 상태관리에 대한 버그 발생 가능성이 더욱 커진다. 이와 같은 상황에서 버그를 줄이는 것의 핵심은 상태관리를 최대한 단순화 시키는 것이다.
SwiftUI에서 변화하는 상태에 대응하는 콜백 메서드를 하나의 메서드로 압축시켰다.
바로 View Protocol 의 body이다. 아무리 여러가지 상태라도 SwiftUI에서는 결국 body라는 단일 상태관리로 퉁칠 수 있게된다.
참고 출처
WWDC19 Introducing SwiftUI: https://developer.apple.com/videos/play/wwdc2019/204/
'Flutter' 카테고리의 다른 글
| Combine | 2. Operators and Subjects (0) | 2024.05.07 |
---|---|
ViewController의 생명주기 (0) | 2024.05.06 |
| Combine | 1. Getting Started (0) | 2024.05.05 |
UserDefaults 를 사용할 때 객체에 Codable 을 채택한 이유 (0) | 2024.05.05 |
WWDC 19 SwiftUI Essentials (0) | 2024.04.22 |