SwiftUI로 바인딩을 하려면 아래 다섯가지를 알아둬야한다.
1. ObservableObject protocol
protocol ObservableObject : AnyObject
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)
cancellable = john.objectWillChange
.sink { _ in
print("\(john.age) will change")
}
print(john.haveBirthday())
// Prints "24 will change"
// Prints "25"
2. @Published
@propertyWrapper struct Published<Value>
class Weather {
@Published var temperature: Double
init(temperature: Double) {
self.temperature = temperature
}
}
let weather = Weather(temperature: 20)
cancellable = weather.$temperature
.sink() {
print ("Temperature now: \($0)")
}
weather.temperature = 25
// Prints:
// Temperature now: 20.0
// Temperature now: 25.0
3. @ObservedObject
@propertyWrapper @frozen struct ObservedObject<ObjectType> where ObjectType : ObservableObject
class UserProgress: ObservableObject {
@Published var score = 0
}
struct InnerView: View {
@ObservedObject var progress: UserProgress
var body: some View {
Button("Increase Score") {
progress.score += 1
}
}
}
struct ContentView: View {
@StateObject var progress = UserProgress()
var body: some View {
VStack {
Text("Your score is \(progress.score)")
InnerView(progress: progress)
}
}
}
4. @State
@frozen @propertyWrapper struct State<Value>
struct PlayerView: View {
var episode: Episode
@State private var isPlaying: Bool = false
var body: some View {
VStack {
Text(episode.title)
Text(episode.showTitle)
PlayButton(isPlaying: $isPlaying)
}
}
}
5. @EnvironmentObject
@frozen @propertyWrapper struct EnvironmentObject<ObjectType> where ObjectType : ObservableObject
class GameSettings: ObservableObject {
@Published var score: Int = 0
}
//SceneDelegate.swift file
var settings = GameSettings()
//SceneDelegate의 scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView.environmentObject(settings))
self.window = window
window.makeKeyAndVisible()
}
//SceneDelegate.swift file end
struct ContentView: View {
// 1.
@EnvironmentObject var settings: GameSettings
var body: some View {
NavigationView {
VStack {
// 2.
Stepper(value: $settings.score, in: 1...1000000, step: 1000, label: {
Text("Current Score: \(settings.score)")
}).padding()
// 3.
NavigationLink(destination: ScoreView()) {
Text("Show Current Score")
}
}
}
}
}
struct ScoreView: View {
@EnvironmentObject var settings: GameSettings
var body: some View {
Text("Score: \(settings.score)")
}
}
아래는 추가로 찾은 예제코드(@StateObject라는걸 사용하고있다. iOS14지원)
// Our observable object class
class GameSettings: ObservableObject {
@Published var score = 0
}
// A view that expects to find a GameSettings object
// in the environment, and shows its score.
struct ScoreView: View {
@EnvironmentObject var settings: GameSettings
var body: some View {
Text("Score: \(settings.score)")
}
}
// A view that creates the GameSettings object,
// and places it into the environment for the
// navigation view.
struct ContentView: View {
@StateObject var settings = GameSettings()
var body: some View {
NavigationView {
VStack {
// A button that writes to the environment settings
Button("Increase Score") {
settings.score += 1
}
NavigationLink(destination: ScoreView()) {
Text("Show Detail View")
}
}
.frame(height: 200)
}
.environmentObject(settings)
}
}