Stateμ Binding
μ§λ μκ° @Stateμ @Binding νλ‘νΌν° λνΌμ λν΄ νμ΅νλ€.
1. @State
@State νλ‘νΌν° λνΌλ₯Ό μ¬μ©ν΄μ μν νλ‘νΌν°λ₯Ό μμ±νλ©΄ ν΄λΉ νλ‘νΌν°κ° μ μΈλ λ·°μ λ°μΈλ©ν μ μκ² λλ€.
μ’ λ μ½κ² μ€λͺ νμλ©΄ λ·°μ λ°μΈλ©μ΄ λμ΄ μλ μννλ‘νΌν°μ λ³κ²½μ΄ μΌμ΄λλ©΄ μλμΌλ‘ λ·°κ° κ°±μ λλ€λ λ§μ΄λ€.
μ½λλ‘ μ§μ μ΄ν΄λ³΄μ.
μλ μ½λλ λ²νΌμ ν΄λ¦νλ©΄ μ«μκ° 1μ© μ¦κ°νλλ‘ κ΅¬νν μ±μ΄λ€.
struct ContentView: View {
@State private var number: Int = 0
var body: some View {
VStack {
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
}
}
}
μ±μ μ€νμν€κ³ λ²νΌμ λλ¬λ³΄λ©΄ λλ₯Ό λλ§λ€ μ«μκ° 1μ© μ¦κ°νλ κ²μ λ³Ό μ μλ€.
μ«μκ° μ¦κ°ν λ€ μ΄λ₯Ό μ°Έμ‘°νκ³ μλ λ·°λ₯Ό κ°±μ νμ§ μμλ μμμ κ°±μ λλ€.
κ·Έλ λ€λ©΄ @Bindingλ 무μμΌκΉ?
2. @Binding
μμμ μμ±ν μ½λλ μν νλ‘νΌν°λ₯Ό μ μΈν λ·°μμ μν νλ‘νΌν°λ₯Ό μ§μ μ¬μ©νκ³ μλ€.
μ¦, μ μΈκ³Ό μ¬μ©μ΄ νλμ λ·°(Struct)μμ μ§νλλ€λ λ§μ΄λ€.
κ·Έλ λ€λ©΄ λ©μΈ λ·°(λΆλͺ¨)μμ μ μΈν μν νλ‘νΌν°λ₯Ό μλΈ λ·°(μμ)μμ μ¬μ©νλ€λ©΄ μ΄λ»κ² λ κΉ?
struct ContentView: View {
@State private var number: Int = 0
var body: some View {
VStack {
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
}
}
}
struct SubView: View {
var body: some View {
VStack {
Text("This is SubView")
Text("\(self.number)")
}
.padding()
.background(.gray)
}
}
μ½λλ₯Ό μμ±νκ³ λΉλλ₯Ό μ§ννλ©΄ μ»΄νμΌ μλ¬κ° λ°μνλ€.
SubView λ΄λΆμ number νλ‘νΌν°κ° μ μΈλμ΄ μμ§ μκΈ° λλ¬Έμ΄λ€.
κ·Έλ λ€λ©΄ SubView λ΄λΆμ number νλ‘νΌν°λ₯Ό μ μΈνλ©΄ μ΄λ»κ² λ κΉ?
struct ContentView: View {
@State private var number: Int = 0
var body: some View {
VStack {
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
}
}
}
struct SubView: View {
private var number: Int = 0
var body: some View {
VStack {
Text("This is SubView")
Text("\(self.number)")
}
.padding()
.background(.gray)
}
}
μ΄λ²μ λΉλλ μ μμ μΌλ‘ μ§νλλ€.
νμ§λ§ λ²νΌμ ν΄λ¦ν΄λ μλΈλ·°μ μλ ν μ€νΈλ λ³κ²½λμ§ μλλ€.
SubViewμ numberμ ContentViewμ numberλ μλ‘ λ€λ₯Έ νλ‘νΌν°μ΄κΈ° λλ¬Έμ΄λ€.
κ·Έλ λ€λ©΄ λ κ°λ₯Ό μ°κ²°ν΄μ£Όλ©΄ λ¬Έμ λ₯Ό ν΄κ²°ν΄ μ€ μ μμ§ μμκΉ?
struct ContentView: View {
@State private var number: Int = 0
var body: some View {
VStack {
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
SubView(number: number)
}
}
}
struct SubView: View {
// μμ±μλ₯Ό ν΅ν΄ number μ λ¬
init(number: Int) {
self.number = number
}
private var number: Int = 0
var body: some View {
VStack {
Text("This is SubView")
Text("\(self.number)")
}
.padding()
.background(.gray)
}
}
μμ±μλ₯Ό ν΅ν΄μ λ©μΈ λ·°μ numberλ₯Ό μ λ¬νλλ μλΈ λ·°μμλ νλ©΄μ΄ κ°±μ λλ κ²μ λ³Ό μ μλ€.
μλ‘ μ΄ κΈΈμμ§λ§ @Binding νλ‘νΌν° λνΌλ₯Ό ν΅ν΄μ κ°λ¨ν ννλ‘ μμ±ν μ μλ€.
struct ContentView: View {
@State private var number: Int = 0
var body: some View {
VStack {
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
SubView(number: $number)
}
}
}
struct SubView: View {
@Binding var number: Int
var body: some View {
VStack {
Text("This is SubView")
Text("\(self.number)")
}
.padding()
.background(.gray)
}
}
μμ±μλ₯Ό ν΅ν΄μ νλ‘νΌν°λ₯Ό μ λ¬ν λ°©μκ³Ό μ μ¬νλ€.
μ°¨μ΄μ μ μλΈ λ·°μμ @Binding νλ‘νΌν° λνΌλ‘ λ³μλ₯Ό μ μΈλ§ νλ€λ κ²μ΄λ€.
λ©μΈ λ·°μμλ Argumentλ‘ $numberλ₯Ό μ λ¬νλ€.
μ¬κΈ°μ λͺ μ¬ν΄μΌν κ²μ $(λ¬λ¬)!
$(λ¬λ¬)κΈ°νΈλ₯Ό λΉΌλ¨ΉμΌλ©΄ μ»΄νμΌ μλ¬κ° λ°μνλ€.
μλΈ λ·°μμ Binding<Int> νμΌλ‘ numberλ₯Ό μ μΈνλλ° Intν numberλ₯Ό μ λ¬ν΄μ λ°μνλ νμ μλ¬μ΄λ€.
μ²μ μλνλ λλ‘ μ μμ μΌλ‘ μλνλ κ²μ λ³Ό μ μλ€.
νμ§λ§ μλ¬Έμ μ΄ ν κ°μ§κ° μλ€. π§
μμ±μλ₯Ό ν΅ν΄μ μ λ¬νλ λ°©μλ μλλ° κ΅³μ΄ @Bindingμ΄λΌλ νλ‘νΌν° λνΌκ° λ±μ₯ν μ΄μ λ 무μμΌκΉ?
μ§κΈ μμλ€μ λ·° μ¬μ΄μμ λ¨λ°©ν₯μΌλ‘ λ°μ΄ν°λ₯Ό μ£Όκ³ λ°κ³ μλ€.
λ©μΈ λ·°(ContentView) -> μλΈ λ·°(SubView) λ°©ν₯μΌλ‘, λ€μ λ§ν΄ μλΈ λ·°μ νλΌλ―Έν°λ‘ λ©μΈ λ·°μ νλ‘νΌν°λ₯Ό μ λ¬νκ³ μλ€.
μλ°©ν₯μΌλ‘ λ°μ΄ν°λ₯Ό μ£Όκ³ λ°λλ‘ μ½λλ₯Ό λ³κ²½ν΄λ³΄λ©΄ @Bindingμ μ¬μ©νλ €λ μ΄μ μ λν΄ λͺ ννκ² μ μ μλ€.
struct ContentView: View {
@State private var number: Int = 0
var body: some View {
VStack {
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
SubView(number: self.number)
}
}
}
struct SubView: View {
private var number: Int = 0
init(number: Int) {
self.number = number
}
var body: some View {
VStack {
Text("This is SubView")
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
}
.padding()
.background(.gray)
}
}
μλΈ λ·°μλ λ²νΌμ λ¬μμ SubView κ°λ λ³κ²½ν μ μλλ‘ μ½λλ₯Ό λ³κ²½ν΄μ€¬λ€.
νμ§λ§ μ»΄νμΌ μ€λ₯λ₯Ό λ°μμν¨λ€.
View μμ²΄κ° Structμ΄λ―λ‘ ImmutableνκΈ° λλ¬Έμ΄λ€.
μ»΄νμΌ μμ²΄κ° μλμ§λ§ λ Όλ¦¬μ μΌλ‘ μκ°ν΄λ³΄λ©΄ μ°λ¦¬κ° ꡬννλ €λ κΈ°λ₯μ μΌλ°μ μΈ νλ‘νΌν°λ‘λ λΆκ°λ₯νλ€λ κ²μ μ μ μλ€.
λ©μΈ λ·° λ΄λΆμ μλΈ λ·° μΈμ€ν΄μ€λ₯Ό μμ±νκ³ νλΌλ―Έν°λ‘ νλ‘νΌν° κ°μ μ λ¬νκ³ μλ€.
λ©μΈ λ·°μμλ μλΈ λ·°μ νλ‘νΌν°λ₯Ό μ κ·ΌνκΈ° μν΄μ , μλΈ λ·° λ΄λΆμ λ©μΈ λ·° μΈμ€ν΄μ€λ₯Ό μμ±νμ¬ νλΌλ―Έν°λ‘ μ λ¬νκΈ° λλ¬Έμ΄λ€.
κ·Έλ λ€λ©΄ μ΄ κΈ°λ₯μ ꡬνν μ μλ κ²μΌκΉ?
μ΄ λ, @Binding νλ‘νΌν° λνΌλ₯Ό μ¬μ©νλ©΄ λλ€!
struct ContentView: View {
@State private var number: Int = 0
var body: some View {
VStack {
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
SubView(number: $number)
}
}
}
struct SubView: View {
@Binding var number: Int
var body: some View {
VStack {
Text("This is SubView")
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
}
.padding()
.background(.gray)
}
mutating func addNumber() {
self.number += 1
}
}
μ μμ μΌλ‘ μ»΄νμΌμ΄ μ μμ μΌλ‘ μ§νλκ³ μ±μ μ€νν΄λ³΄λ©΄ λ©μΈ λ·°μ numberμ μλΈ λ·°μ numberκ° κ°μ κ°μ κ°μ§κ³ μκ³ , μλ°©ν₯μΌλ‘ λ°μ΄ν°λ₯Ό μ£Όκ³ λ°κ³ μλ κ²μ λ³Ό μ μλ€!
μ΄κ²μ΄ λ°λ‘ @Bindingμ μ¬μ©νλ μ΄μ μ΄λ€.
νμ§λ§ @Binding μμ λ¨μ μ μ‘΄μ¬νλ€.
μμ λ§νλ κ²μ²λΌ μν νλ‘νΌν°λ νλ‘νΌν°λ₯Ό μ μΈν λ·°μμλ§ μ κ·Όμ΄ κ°λ₯νλ€.
νμ λ·°κ° μλκ±°λ λ°μΈλ©μ΄ ꡬνλμ΄ μμ§ μμΌλ©΄ λ€λ₯Έ λ·°μμ μ κ·Όμ΄ λΆκ°λ₯νλ€.
λν λ·° μ체μ μ’ μμ μΈ κ°λ μ΄λ―λ‘ λ·°κ° μ¬λΌμ§λ©΄ νλ‘νΌν° μμ μ¬λΌμ§λ€.
μ΄λ¬ν λ¬Έμ λ₯Ό ν΄κ²°ν΄μ£Όλ κ²μ΄ Observable κ°μ²΄λ€.
μμ λ§ν λ¬Έμ μ λ€μ ν΄κ²°νκ³ , λ€λ₯Έ λ·°μμ μ κ·Όν μ μλ μꡬμ μΈ λ°μ΄ν°λ₯Ό νννκΈ° μν΄ μ¬μ©νλ€.
Observable κ°μ²΄
μλ μ½λμ λΉλλ μ±μ 보면 @Binding νλ‘νΌν° λνΌλ₯Ό μ¬μ©ν΄μ, νμ΄μ§κ° λ³κ²½λμ΄λ νλμ κ°μ κ°λ₯΄ν€κ³ μ΄λ₯Ό λ³κ²½νκ³ μλ€.
struct ContentView: View {
@State private var number: Int = 0
var body: some View {
NavigationView {
VStack {
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
SubView(number: $number)
NavigationLink(destination: SecondView(number: $number)) {
Text("Second Viewλ‘ μ΄λ")
}
}
}
}
}
struct SubView: View {
@Binding var number: Int
var body: some View {
VStack {
Text("This is SubView")
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
}
.padding()
.background(.gray)
}
}
struct SecondView: View {
@Binding var number: Int
var body: some View {
VStack {
Text("This is Second View")
Text("\(self.number)")
Button(action: {
self.number += 1
}) {
Text("λλ¬μ£ΌμΈμ!")
}
}
.padding()
.background(.gray)
}
}
νμ§λ§ λ©μΈ λ·° λ΄λΆμ Second Viewκ° μ’ μμ μΌλ‘ μ μΈλμ΄ μκ³ , λ§€λ² @Bindingλ₯Ό λ¬μμ€ νλ‘νΌν°λ₯Ό μ μΈν΄μΌ νλ€.
λ¨μν νλμ νμ΄μ§(λΆλͺ¨)μ νλ‘νΌν°λ₯Ό λ€λ₯Έ νμ΄μ§(μμ)μμ μ¬μ©νλ κ²½μ°μλ κΈ°μ‘΄ λ°©μλλ‘ @BindingμΌλ‘ μ λ¬ν΄λ λμ§λ§, νμ΄μ§ μ΄λμ΄ μ¦μμ§λ©΄ λ§€λ² μ§μ μ°κ²°ν΄μ€μΌ νλ―λ‘ λ²κ±°λ‘λ€.
μ΄λ° λ¬Έμ λ€μ Observableμ΄ ν΄κ²°ν΄μ€λ€.
ViewModelκ³Ό λΉμ·ν μν μ μννλλ°, νΉμ μν©μ λ°λΌ λ³κ²½λλ λ°μ΄ν°λ₯Ό μμ§νκ³ κ΄λ¦¬νλ μν μ μννλ€κ³ λ³Ό μ μλ€.
Observable κ°μ²΄λ Observer κ°μ²΄μ νλμ μΈνΈλ₯Ό μ΄λ£¬λ€.
Observable κ°μ²΄λ νλ‘νΌν°λ₯Ό κ²μ(Publish)νκ³ Observer κ°μ²΄λ μ΄λ₯Ό ꡬλ νκ³ μλ€.
import Foundation
import Combine
class CustomNumber: ObservableObject {
@Published var number = 0
func increateNumber() {
self.number += 1
}
}
struct ContentView: View {
@ObservedObject var number: CustomNumber
var body: some View {
NavigationView {
VStack {
Text("\(self.number.number)")
Button(action: {
self.number.increateNumber()
}) {
Text("λλ¬μ£ΌμΈμ!")
}
SubView(number: number)
NavigationLink(destination: SecondView(number: number)) {
Text("Second Viewλ‘ μ΄λ")
}
}
}
}
}
struct SubView: View {
@ObservedObject var number: CustomNumber
var body: some View {
VStack {
Text("This is SubView")
Text("\(self.number.number)")
Button(action: {
self.number.increateNumber()
}) {
Text("λλ¬μ£ΌμΈμ!")
}
}
.padding()
.background(.gray)
}
}
struct SecondView: View {
@ObservedObject var number: CustomNumber
var body: some View {
VStack {
Text("This is Second View")
Text("\(self.number.number)")
Button(action: {
self.number.increateNumber()
}) {
Text("λλ¬μ£ΌμΈμ!")
}
}
.padding()
.background(.gray)
}
}
κΈ°μ‘΄μ @BindingμΌλ‘ μμ±ν μ½λμ λΉκ΅ν΄λ³΄λ©΄ number μ¦κ°μ λν λ‘μ§μ ObservableObject νλ‘ν μ½μ μ±νν CustomNumberμμ λ΄λΉνκ³ μλ κ²μ λ³Ό μ μλ€.
Environment κ°μ²΄
number μ¦κ°μ λν λ‘μ§μ CustomNumber ν΄λμ€λ‘ λΆλ¦¬νμ§λ§ μ¬μ ν Navigationμ μ§νν λ ꡬλ κ°μ²΄μ λν 참쑰체λ₯Ό μ λ¬ν΄μΌ νλ€.
μν©μ λ°λΌ λ€λ₯΄μ§λ§ μ± λ΄μ μ¬λ¬ λ·°κ° λμΌν ꡬλ κ°μ²΄μ μ κ·Όν΄μΌνλ κ²½μ°μλ 볡μ‘ν΄μ§ μ μλ€.
μ΄λ΄ λ μ¬μ©νλ κ²μ΄ Environment κ°μ²΄λ€.
λ°©λ²μ Observable κ°μ²΄μ λμΌνμ§λ§ λ·°μμ λ·°λ‘ μ λ¬ν νμ μμ΄ λͺ¨λ λ·°κ° μ κ·Όν μ μλ€λ κ²μ΄λ€.
import SwiftUI
@main
struct _21024_ObservableApp: App {
let customNumber: CustomNumber = CustomNumber()
var body: some Scene {
WindowGroup {
ContentView().environmentObject(customNumber)
}
}
}
νμ§λ§ μ¬μ©νκΈ° μ μ Senceμμ κ°κ°μ λ·°μμ μ°Έμ‘°νλ €λ ObservableObjectλ₯Ό λ±λ‘ν΄μ€μΌ νλ€.
struct ContentView: View {
@EnvironmentObject var number: CustomNumber
var body: some View {
NavigationView {
VStack {
Text("\(self.number.number)")
Button(action: {
self.number.increateNumber()
}) {
Text("λλ¬μ£ΌμΈμ!")
}
SubView()
NavigationLink(destination: SecondView()) {
Text("Second Viewλ‘ μ΄λ")
}
}
}
}
}
struct SubView: View {
@EnvironmentObject var number: CustomNumber
var body: some View {
VStack {
Text("This is SubView")
Text("\(self.number.number)")
Button(action: {
self.number.increateNumber()
}) {
Text("λλ¬μ£ΌμΈμ!")
}
}
.padding()
.background(.gray)
}
}
struct SecondView: View {
@EnvironmentObject var number: CustomNumber
var body: some View {
VStack {
Text("This is Second View")
Text("\(self.number.number)")
Button(action: {
self.number.increateNumber()
}) {
Text("λλ¬μ£ΌμΈμ!")
}
}
.padding()
.background(.gray)
}
}
κΈ°μ‘΄ λ°©μκ³Ό λ€λ₯΄κ² λ·°μ λ·° μ¬μ΄ κ°μ Navigationμ μ§νν λ 맀κ°λ³μλ‘ λκ²¨μ£Όμ§ μμλ λλ€λ μ₯μ μ΄ μλ€.
μ¬μ€ @State, @Binding, @ObservedObject, @EnvironmentObject μ€μ μ΄λ κ²μ μΈ μ§λ κ°λ°μ λ§μμ΄κ³ μ΄λ»κ² ꡬννλλμ λ°λΌ λ¬λΌμ§λ€κ³ μκ°νλ€.
κ·Έλλ κ° νλ‘νΌν° λνΌλ³λ‘ μ₯μ μ΄ μμΌλ, μ₯μ μ λ§κ² μ¬μ©νλ©΄ λ λ―νλ€.
μ 리
νλμ λ·°, νΉμ νΉμ λ·°μ μ’ μμ μΈ λ·°μμ λ¨λ°©ν₯μΌλ‘ λ°μ΄ν°λ₯Ό μ£Όκ³ λ°μ λ -> @State
μλ°©ν₯μΌλ‘ λ°μ΄ν°λ₯Ό μ£Όκ³ λ°μ λ -> @Binding
μλ°©ν₯μΌλ‘ μ£Όκ³ λ°μΌλ©΄μ, λ‘μ§μ λΆλ¦¬νκ³ μΆμ λ -> @ObservedObject
λͺ¨λ λ·°μμ μ°Έμ‘°ν μ μλ λ°μ΄ν°μ λ‘μ§μ λΆλ¦¬νκ³ μΆμ λ -> @EnvironmentObject
π νκ³
Environment κ°μ²΄μ κ²½μ° Flutterμ Providerμ λ§€μ° μ μ¬ν ννλ₯Ό μ§λ λ€. Providerλ₯Ό ν΅ν΄ νμ μμ ―μμ λ°μ΄ν°λ₯Ό μ κ·Όν μ μλλ° μ΄κ²κ³Ό μμ ν λκ°μλ€. ν κ°μ§ κΆκΈν μ μ Flutterμμλ κ°μ λ³κ²½μ΄ μΌμ΄λλ©΄ ν΄λΉ μμ ―μ μ λΆ λ€μ λ λλ§μ μ§ννλ€. (Consumerλ₯Ό μ μ©ν΄μ νΉμ λΆλΆ λ λλ§λ κ°λ₯νλ€.) SwiftUIμμλ μ체μ μΌλ‘ νΉμ λΆλΆλ§ λ λλ§μ νλκ±΄μ§ μ λΆ λ λλ§μ μ§ννλ κ²μΈμ§ μ’ λ μμλ΄μκ² λ€.