struct ContentView: View {
@State private var isPlaying: Bool = false
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)
PlayButton(isPlaying: $isPlaying) // Binding
}
}
}
struct PlayButton: View {
@Binding var isPlaying: Bool
var body: some View {
Button(isPlaying ? "Pause" : "Play") {
isPlaying.toggle()
}
}
}
PlayButton(isPlaying: $isPlaying)
→$
: State 변수의 참조를 생성하여 해당 변수의 상태를 다른 뷰나 속성과 양방향으로 Binding 할 수 있도록 도와줌
ObservableObject | Apple Developer Documentation
💡 PropertyWrapper가 아닌 클래스 프로토콜!
objectWillChange
publisher를 가지고 있음)class Contact: ObservableObject {
@Published var name: String
@Published var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func haveBirthday() -> Int {
age += 1
return age
}
}
let john = Contact(name: "John Appleseed", age: 24)
let cancellable = john.objectWillChange
.sink { _ in
print("\(john.age) will change") // 24 will change
}
print(john.haveBirthday()) // 25
class User: ObservableObject {
@Published var age = 10
}
struct ContentView: View {
@ObservedObject var user: User
var body: some View {
Button("Plus Age") {
user.age += 1
}
}
}
@StateObject vs @ObservedObject
▪︎ 인스턴스를 최초로 생성하는 경우 → @StateObject
▪︎ 하위 뷰에서 주입받는 경우 → @ObservedObject
struct ContentView: View {
@Environment(\.colorScheme) var colorScheme
var body: some View {
Text("Hello, World!")
.foregroundStyle(colorScheme == .dark ? .white : .black)
}
}
class Info: ObservableObject {
@Published var age = 10
}
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
MainView()
.environmentObject(Info())
}
}
}
struct MainView: View {
@EnvironmentObject var info: Info
var body: some View {
Button {
self.info.age += 1
} label: {
Text("Click Me for plus age")
}
SubView()
}
}
struct SubView: View {
@EnvironmentObject var info: Info
var body: some View {
Button {
self.info.age -= 1
} label: {
Text("Click Me for minus age")
}
}
}
⚠️ @EnvironmentObject 사용의 문제점
1. 데이터 의존성 문제 발생: 해당 객체에서 의존성이 앱 전체로 퍼질 수 있어 코드 가독성과 유지 보수가 어려워지고, 예기치 않은 버그를 유발할 수 있음.
2. 데이터 관리의 복잡도 증가: 여러 뷰에서 동일한 EnvironmentObject를 참조하고 수정하면 데이터의 일관성을 유지하기가 힘들어짐.
3. 테스트의 어려움: EnvironmentObject에 의존하면 단위 테스트나 UI 테스트를 작성하기 어려워짐. (각 테스트케이스마다 필요한 환경객체들을 설정해줘야 하는데 이는 오버헤드를 초래하게 됨.)
최대한 구제적인 범위 안에서는 @State, @Binding, @ObservedObject를 사용하고 정말 필요할 때, 전역적으로 공유되어야 하는 상태에서만 @EnvironmentObject를 사용하는 것이 바람직함.