[SwiftUI] @State, @Binding, @AppStorage, @SceneStroage, @FetchRequest
SwiftUI 에서 사용되는 Property Wrappers 를 정리해보자.
@State
SwiftUI 관련해서 강좌나 예제 코드를 보면 거의 처음 마주하는 키워드다.
https://developer.apple.com/documentation/swiftui/state
변수 값이 바뀌면 변수와 연결된 View를 업데이트 한다.
struct PlayButton: View {
@State private var isPlaying: Bool = false
var body: some View {
Button(isPlaying ? "Pause" : "Play") {
isPlaying.toggle()
}
}
}
RxSwift 의 Observe 기능을 한줄로 줄여버렸다.
@Binding
@State 변수를 자식 뷰로 전달해 값을 수정할 때 사용한다. 부모 뷰는 State를, 자식 뷰는 Binding으로 선언한다.
자식 뷰에서 Binding 값이 변경되면, 연결된 부모 뷰의 State 값도 변경되며, View가 업데이트된다.
struct PlayButton: View {
@Binding var isPlaying: Bool
var body: some View {
Button(isPlaying ? "Pause" : "Play") {
isPlaying.toggle()
}
}
}
struct PlayerView: View {
var episode: Episode
@State private var isPlaying: Bool = false
var body: some View {
VStack {
Text(episode.title)
.foregroundStyle(isPlaying ? .primary : .secondary)
// Pass a binding.
// $ 기호를 붙여 Binding 변수로 전달한다.
PlayButton(isPlaying: $isPlaying)
}
}
}
주로 부모-자식처럼 여러 뷰에서 공유되는 데이터보다는 2~3개의 뷰에서 공유되는 데이터에 많이 사용하는듯 하다.
@AppStorage
UserDefaults를 사용해봤다면 이해하기 쉽다.
// UserDefaults에 값 저장
UserDefaults.standard.set({Value},forKey: "USER_DEFAULTS_KEY")
// UserDefaults에 저장된 값 호출
UserDefaults.standard.value(forKey: "USER_DEFAULTS_KEY")
해당 UserDefaults 기능에 @State를 합친 기능을 한다.
// 해당 키로 저장된 값을 불러와 AppStorageValue 저장 만약 값이 nil일 경우 0으로 초기화 및 저장
@AppStorage("APP_STORAGE_KEY") private var AppStorageValue = 0
...
// 변수에 새롭게 저장된 값을 키로 UserDefaults에 동기화 및 연결된 View 업데이트
AppStorageValue = 10
UserDefaults에 저장할 뿐 아니라 해당 값에 의존된 View까지 업데이트해준다.
@SceneStorage
iOS 14 부터 사용이 가능하다. Scene의 개념이 필요하기에 사실상 iPadOS에서 주로 사용된다.
iPadOS에서 Multiple windows 옵션이 true일 경우, 여러 Window를 띄울 수 있게 되는데 해당 Window를 하나의 Scene이라고 한다.
// Scene(Window)이 여러개 일때, 모든 윈도우 프로세스에서 동기화
// ex) Scene1에서 해당 값을 변화할때, Scene2에서도 값 변화 및 의존되는 View 업데이트
@AppStorage("APP_STORAGE_KEY") private var AppStorageValue = 0
// Key가 같더라도 각 Scene(Window)마다, 다른 상태 값을 저장
// Scene(Window)마다 값의 영향을 주지 않음
@SceneStorage("SCENE_STORAGE_KEY") private var SceneStorageValue = 0
iOS에서는 Multiple windows 옵션이 없기 때문에 사실상 @AppStorage와 @SceneStroage가 큰 차이가 없다.
따라서 iPadOS 중에서도 Multiple windows 옵션이 존재하는 앱을 개발한다면 신경써야할 문제이다.
@FetchRequest
@AppStorage와 @SceneStroage가 UserDefaults와 관련된 키워드 였다면, @FetchRequest는 CoreData와 관련이 있다.
CoreData에서 Entity를 사용하기 전에 부모 뷰로부터 환경변수를 설정해줘야한다.
class DataController: ObservableObject {
var container: NSPersistentContainer
init(containerName: String) {
self.container = NSPersistentContainer(name: containerName)
self.container.loadPersistentStores { description, error in
if let error = error {
print("Core Data Failed to load: \(error.localizedDescription)")
return
}
self.container.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
}
}
}
...
@StateObject private var dataController = DataController(containerName: "{SC_DATA_MODELD}")
...
ContentView()
.environment(\.managedObjectContext,
self.dataController.container.viewContext)
// 부모 View로부터 받은 환경 변수
@Environment(\.managedObjectContext) var moc
@FetchRequest(sortDescriptors: []) var fetchedResults: FetchedResults<{COREDATA_ENTITY}>
// 또는
// predicate: 필터 또는 정렬 적용
@FetchRequest(sortDescriptors: [], predicate: NSPredicate(format: "{PREDICATE}")) var fetchedResults: FetchedResults<{COREDATA_ENTITY}>
@AppStorage, @SceneStroage 처럼 CoreData를 동기화 할 수 있다.
@StateObject, @Environment처럼 아직 모르는 개념이 있지만 계속해서 알아보자.