WWDC23 이후 완전히 개편된 데이터 상태 관리에 대한 방법입니다.
iOS 17 이후 Observation 프레임워크의 @Observable
Macro를 사용하여 SwiftUI의 데이터 흐름을 다룰 수 있게 되었다.
ObservavleObject
프로토콜을 채택하는 대신에,
상태 관리할 클래스 또는 구조체 위에 @Observable
매크로를 표시한다.
@Observable
class Library {
var books: [Book] = [Book(), Book(), Book()]
}
이전처럼 내부 프로퍼티에 추가로 프로퍼티 래퍼 @Published
를 사용할 필요 없다.
대신, 속성을 상태 관리에서 제거하려면 속성에 @ObservationIgnored
매크로를 사용하면 된다.
SwiftUI 는 observable 한 속성들이 업데이트 되고, 뷰의 body 가 그 속성을 바로 읽을때만 뷰를 업데이트 한다.
body 에게 읽하지 않는 변수가 변경될때는 뷰를 업데이트 하지 않는다.
마찬가지로, 모델을 클래스로 사용하고 있다면 ObservableObject
프로토콜을 채택하고 @Published
프로퍼티 래퍼를 사용했을것이다. 그것을 없애고 @Observable
매크로만 작성해주자.
-> 이 경우에 뷰에서 해당 모델을 사용할 때 @State
조차 붙혀주지 않아도 된다. @Observable
매크로를 작성한 클래스는 내부 속성의 변화를 알아서 감지해서 body 를 업데이트 한다.
ObservavleObject
를 사용한 객체에는 @StateObject
를 적어줬어야 하는데,
이제는 @Observable
을 사용한 참조 타입은 값 타입과 마찬가지로, @State
를 적어주면 된다.
다음 앱 구조는 Library
인스턴스를 만들고, StateObject 로 저장한 후 .environmentObject
로 환경 값으로 넣어줬다.
// BEFORE
@main
struct BookReaderApp: App {
@StateObject private var library = Library()
var body: some Scene {
WindowGroup {
LibraryView()
.environmentObject(library)
}
}
}
// AFTER
@main
struct BookReaderApp: App {
@State private var library = Library()
var body: some Scene {
WindowGroup {
LibraryView()
.environment(library)
}
}
}
@Observable
을 사용했으면 @State
로 선언하고 .environment
로 넣어주면 된다.
그리고 LibraryView 안에서는 다음과 같이 사용한다.
// BEFORE
struct LibraryView: View {
@EnvironmentObject var library: Library
var body: some View {
List(library.books) { book in
BookView(book: book)
}
}
}
// AFTER
struct LibraryView: View {
@Environment(Library.self) private var library
var body: some View {
List(library.books) { book in
BookView(book: book)
}
}
}
단, Observable 타입의 뷰가 바인딩이 필요해지면, @ObservedObject
을 지우고, @Bindable
프로퍼티 래퍼를 작성한다.
@Bindable
은 @Observable
을 사용한 클래스의 프로퍼티에 대한 바인딩을 생성할 수 있도록 한다.