일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- Network
- 네트워크
- iphone
- UIKit
- Concurrency
- combine
- authentication
- GCD
- fullscreencover
- 달력
- state
- gesture
- dataflow
- firebase
- SwiftUI
- stateobject
- Animation
- RxSwift
- CS
- Performance
- realitykit
- 데이터최적화
- WWDC
- ios
- swift
- environmentobjet
- auth
- withAnimation
- ar
- arkit
- Today
- Total
XLOG
[SwiftUI] Observation (feat iOS 17, 써야하는 이유) 본문
1. Observation 이란?
wwdc 23 에서 발표한 observation 은 프로퍼티의 변화를 추적하는 Swift 기능으로 같은 wwdc 23 에 발표한 swift 5.9에 신기능인 매크로를 사용하여 정의한 데이터 타입을 observable 하게 바꿔주는 기능이다.
2. 사용방법
정의한 class 에 @observable property wrapper 를 붙여준다.
import Foundation
import Observation
@Observable class DataModel {
var count: Int = 0
}
이를 View 에서 사용할 땐 @State, @Environment, @Bindable, var 를 사할 수 있다. 여기서의 기준은
View의 부분일 경우 @State, 글로벌하게 변수를 사용할 경우 @Environment(Type.self) var, 단순히 바인딩이 필요할 경우(TextField 같이 값의 변화를 주기 위함) @Bindable 그게 아니라면 var 를 사용하면 된다.
3. 잘 사용하고 있는 ObservableObject 에서 Observable 을 사용해야 하는 이유
- 간단하게 정의한 데이터 타입자체에 Observable 매크로를 사용하여 ViewModel 처럼 활용이 가능하다.
- View 를 Re-render 하는 기준이 다르기 때문에 불필요한 Re-render를 최소화 할 수 있다.
기존 ObservedObject, StateObject, EnvironmentObject 의 경우 내부 프로퍼티 의 변화가 발생하면 해당 객체를 갖고 있는 모든 View는 변화를 감지하여 Re-render 가 이루어진다. 이게 State 와의 가장 큰 차이점이었다. @State 의 경우 변수를 mutate 시키더라도 이를 view 에서 직접적으로 사용하지 않는다면 view 를 re-render 를 시키지 않는다. @Observable 의 경우 사용할때 @State, @Environment 등을 사용하는 것 처럼 내부 프로퍼티의 변화가 있더라도 해당 객체의 변화하는 프로퍼티를 직접 view 에서 사용하지 않는다면 Re-render 를 발생시키지 않는다. 즉 불필요하 Re-render 를 최소화 할 수 있다.
import SwiftUI final class OriginalObservable: ObservableObject { @Published var count: Int = 0 func add() { self.count += 1 } func minus() { self.count -= 1 } } struct OriginalSubView1: View { @EnvironmentObject var vm: OriginalObservable var body: some View { VStack { let _ = Self._printChanges() Text("\(vm.count)") HStack { Button(action: { vm.minus() }) { Text("-") } Button(action: { vm.add() }) { Text("+") } } } } } struct OriginalSubView2: View { @EnvironmentObject var vm: OriginalObservable var body: some View { VStack { let _ = Self._printChanges() Text("Original Subview2") } } } struct ContentView: View { // 07:29 var body: some View { VStack { OriginalSubView1() OriginalSubView2() } } }
위에 코드를 보게 되면 OriginalSubView2 의 경우 OriginalSubView1 과 같은 EnvironmentObject 를 가지고 있다. 하지만 View에서 OriginalObservable 타입의 어떠한 프로퍼티도 View에서 사용하고 있지 않다.(극적인 예시를 위해.....불필요한 view model 을.....)
동작을 살펴보면
같은 EnvironmentObject를 가지고 있는 모든 View 는 ViewModel 의 변화를 감지하고 View를 Re-render를 시킨다.
그럼 새롭게 도입된 Observable을 확인해보자.
import SwiftUI import Observation @Observable final class NewObservable { var count: Int = 0 func add() { self.count += 1 } func minus() { self.count -= 1 } } struct NewSubview1: View { @Environment(NewObservable.self) var vm: NewObservable var body: some View { VStack { let _ = Self._printChanges() Text("\(vm.count)") HStack { Button(action: { vm.minus() }) { Text("-") } Button(action: { vm.add() }) { Text("+") } } } } } struct NewSubview2: View { @Environment(NewObservable.self) var vm: NewObservable var body: some View { VStack { let _ = Self._printChanges() Text("New Subview2") } } } struct ContentView: View { var body: some View { VStack { NewSubview1() NewSubview2() } } }
아까와 동일한 구조를 보이지만 New Subview2 의 경우 Re-render가 발생하지 않는 것을 확인할 수 있다.
- 추적할 프로퍼티에 @Published property wrapper 를 붙여줄 필요가 없다.(코드가 짧아진다)
등의 이유가 있다.
4. 느낌점
여기서 가장 흥미로운 점은 2번째이다. 몇일전 View Re-render 원리에 대한 공부를 했을 때 ViewModel 로 채택한 ObservableObject 는 하나의 프로퍼티의 변경으로 채택한 모든 View 의 변화를 만들어 냈고, 그렇기에 ViewModel 의 설계에 의한 데이터 흐름을 잘 설계해야한다는 것을 느꼈는데, iOS17 부터는 Observable 매크로를 통해서 이 부분을 조금 더 쉽게 효율적인 앱의 동작을 이끌어 낼 수 있다는 점이었다. 요즘 iOS 15, 16 을 최소버전으로 쓰고 있는 앱들이 많은 만큼 곧 iOS17 이 최소버전인 앱들도 생겨날 것이기에, 그 준비를 위해 Observable 을 사용하는 것을 고려해보는 것도 좋을 것 같다.
'Swift > SwiftUI' 카테고리의 다른 글
[최적화] View 의 Update 를 최소화 하는 방법 (0) | 2024.07.01 |
---|---|
[DataFlow] State, Binding, StateObject, ObservedObject, EnvironmentObject 는 무엇이고 차이는? (0) | 2024.07.01 |
[SwiftUI] Environment 활용하기 (0) | 2024.06.25 |
[SwiftUI] 밀리의 서재 책정보 Sheet 애니메이션 아이디어 및 구현 (0) | 2024.06.24 |
[SwiftUI] View 의 Size 구하기 (0) | 2024.05.19 |