Starbucks Caramel Frappuccino
본문 바로가기
  • 그래 그렇게 조금씩
SwiftUI/SwiftUI(examples)

Data Essentials in SwiftUI #WWDC20

by Toughie 2023. 5. 10.

https://developer.apple.com/videos/play/wwdc2020/10040/

0. Data for a new view
What data does this view need to do its job?
How will the view manipulate that data? (데이터가 변하는가 안변하는가? _var let)

Where will the data come from?
* Source of Truth

 

struct BookCard: View {
    let book: Book
    let progress: Double
    
    var body: some View {
        HStack {
            BookCover(book.coverName)
            VStack(alignment: .leading) {
                TitleText(book.title)
                AuthorText(boo.author)
            }
            Spacer()
            RingProgressView(value: progress)
        }
    }
}

데이터들은 BookCard가 초기화 될 때 슈퍼뷰에서 전달됨.

슈퍼뷰의 바디가 실행될 때마다 새로운 북카드가 매번 초기화됨

초기화된 객체는 SwiftUI가 렌더링 할 정도로 충분히 남아있다가 사라짐.

 

가독성, 테스트를 위한 코드 분리

뷰는 임시적으로 존재함.
- SwiftUI가 렌더링을 완료하면 struct 객체가 사라진다는 말
하지만 @State 프로퍼티 래퍼를 사용하면 SwiftUI가 이 객체를 유지함.

프레임워크가 이 뷰를 렌더링 할 필요가 있을 때 구조체를 다시 초기화하고
존재하는 스토리지에 다시 연결함

 

EditorConfig가 구조체, 즉 값타입이기 때문에 BookView에서 var editorConfig처럼 전달하면
새로운 복사본을 전달함.
이렇게 하면 SwiftUI가 관리하고 있던 원본 값을 조작할 수가 없음.
(하위 뷰인 ProgressEditor와 BookView간 데이터 연결,동기화가 안됨)

EditorConfig에도 @State 프로퍼티를 만들면 되지 않느냐?
State는 새로운 source of truth를 생성한다고 했다.
-> ProgressEditor에서 생긴 변화들은 자신의 state를 만들 뿐이다. (BookView와 공유하는 것이 아니다.)

지금은 하나의 source of truth가 필요하다.
즉 BookView로부터 source of truth에 쓸 수 있는 방법이 필요하다. 
(각 뷰마다 state를 만드는 것이 아니라, source of truth를 하나만 가지고 이것을 공유해야된다는 말이다.)

 

SwiftUI에서 write-access를 공유하기 위한 도구는 Binding이다. 

 

Properties for data that isn't mutated by the view

@State for transient data owned by the view

@Binding for mutating data owned by another view

 

State is designed for transient UI state that is local to a view

클래스에서만 채택 가능한 프로토콜

 

전 뷰에서 공유하는 단일 데이터 모델

뷰마다 필요한 데이터를 전달하기 위해 데이터 모델(ObservableObject)가 여러개 있을 수도 있음.(데이터 모델이 복잡한 경우)

doest not get ownership of the instance you're providing to it
-> 그래서 해당 객체의 라이프 사이클을 직접 관리해줘야함.

SwiftUI가 OservableObject의 objectWillChange를 구독함

ObservableObject가 변할 예정이면(will change), ObservableObject에 의존하는 뷰들이 전부 업데이트 될 것(will change).


근데 왜 did change가 아니라 will change 인가?

SwiftUI가 어떤것들이 곧 변하려는지 알고, 이러한 변화들을 한꺼번에 한 번의 업데이트에 적용시키기 때문이다.

ObservableObject의 어떤 값타입에 $만 붙여서 바인딩을 만들 수 있음.

 

뷰의 라이프 사이클과 함께함(생성/소멸)
바디파트 실행 이전에 초기화됨.

@StateObject인 CoverImageLoader()는 뷰가 그려질 때 초기화 되는 것이 아니라,
body가 실행되기 직전에 초기화 된다. 그리고 전체 뷰 생명주기 동안 살아있다.
뷰가 더이상 필요없어지면 SwiftUI가 알아서 메모리에서 해제시킨다.(onDisappear 등에서 직접 해제시켜줄 필요 없음)

같은 객체를 수많은 하위 뷰에 전달함.
그런데 만약 우측 사진과 같이 특정 뷰에만 ObservableObject가 필요한 경우라면?
EnvironmentObject는 뷰 모디파이어도 되고 프로퍼티 래퍼도 된다.

부모 뷰에서 view modifier로 사용하고
하위 뷰에서 프로퍼티 래퍼를 통해 ObservableObject의 객체를 읽을 수 있다.

프레임워크가 필요한 곳에만 값을 전달하고, 값을 읽을 때만 의존하는 것으로 간주한다.

 

ObservableObject와 StateObject의 주요한 차이점 중 하나는 메모리 관리이다.
ObservableObject는 객체가 메모리에서 자동으로 해제되지 않는다.(그래서 onDisappear 등에서 해제시켜줘야함)
StateObject는 해당 뷰의 수명주기와 함께 메모리에서 자동으로 해제됨. (객체가 더이상 필요없을 때 자동으로 메모리에서 해제돼서 메모리 누수를 방지할 수 있음)

 

 SwiftUI가 화면을 다시 만들거나 그릴 가능성이 있는 경우에

 내부에 @ObservedObject를 쓰는 것은 안전하지 않음.

 @StateObject를 사용하는 것이 화면이 다시 그려져도 항상 같은 결과를 얻을 수 있음.

 

SwiftUI system에서 view의 정의와 역할

view is simply a definition of a piece of UI

SwiftUI uses this definition to create the appropriate rendering.

UI에서 이벤트가 발생
클로저 등 액션 실행
이는 Source of Truth를 변화시킴
Source of Truth의 변화에 맞게 새롭게 업데이트 된 뷰를 복사. (for 렌더링)
이에 맞게 렌더링

Drivers of change in app's views

 

해당 데이터를 사용하고 있는 뷰가 데이터를 가지고 있는가?
아니면 상위 뷰에서 데이터를 가지고 있는가? 아니면 아예 다른 앱 내 서브시스템?


share data with a common ancestor.
prefer StateObject as a view-owned source of truth for ObservableObjects.
consider placing global data in the app.

 

State, StateObject, Constant는 Process Lifetime이기에 앱을 종료하거나 폰을 재시작하면 사라짐.
-> 이러한 한계를 극복하기 위해 씬/앱스토리지가 등장함.

 

'SwiftUI > SwiftUI(examples)' 카테고리의 다른 글

모델? 뷰모델?  (0) 2023.05.13
ProgressBar 진행바 만들기 / GeometryReader/ available size  (0) 2023.05.09