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์์๋ ์์ฒด์ ์ผ๋ก ํน์ ๋ถ๋ถ๋ง ๋ ๋๋ง์ ํ๋๊ฑด์ง ์ ๋ถ ๋ ๋๋ง์ ์งํํ๋ ๊ฒ์ธ์ง ์ข ๋ ์์๋ด์๊ฒ ๋ค.
'๐ป ๊ฐ๋ฐ > iOS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
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์์๋ ์์ฒด์ ์ผ๋ก ํน์ ๋ถ๋ถ๋ง ๋ ๋๋ง์ ํ๋๊ฑด์ง ์ ๋ถ ๋ ๋๋ง์ ์งํํ๋ ๊ฒ์ธ์ง ์ข ๋ ์์๋ด์๊ฒ ๋ค.