๐Ÿ‘€ Property Wrapper๋ž€?

@ObservedObject์™€ @EnvironmentObject ๋ชจ๋‘ @State์™€ @Binding๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ property wrapper ์ž…๋‹ˆ๋‹ค !

  • Property wrapper๋ž€ ์†์„ฑ ๊ฐ์‹ธ๊ธฐ๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ๋ฅผ ๋”์šฑ ๊ฐ„๊ฒฐํ•˜๊ณ  ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.
  • ์ด๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ๋ฅผ ๋”์šฑ ์ง๊ด€์ ์ด๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ’ก @ObservedObject

SwiftUI View๊ฐ€ ๊ด€์ฐฐํ•ด์•ผ ํ•˜๋Š” ์™ธ๋ถ€ ๊ฐ์ฒด๊ฐ€ ์žˆ์„ ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
@ObservedObject๋Š” ObservableObject ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜์—ฌ SwiftUI View์™€ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค.

๐Ÿ“ Docs

์‚ฌ์ง„


@ObservedObject ๋ž˜ํผ๋Š” SwiftUI ๋ทฐ์™€ ObservableObject ๊ฐ์ฒด ๊ฐ„์˜ ์—ฐ๊ฒฐ์„ ์„ค์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
ObservableObject ๊ฐ์ฒด๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๋ทฐ๋Š” ์•Œ๋ฆผ์„ ๋ฐ›๊ณ  ์—…๋ฐ์ดํŠธ๋œ ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์‹œ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.
์ด๋Ÿฌํ•œ ๋ž˜ํผ๋Š” ๋ทฐ์™€ ๊ด€์ฐฐ ๋Œ€์ƒ ๊ฐ์ฒด ๊ฐ„์— ๋ฐ”์ธ๋”ฉ์„ ์ƒ์„ฑํ•˜์—ฌ, ๊ด€์ฐฐ ๋Œ€์ƒ ๊ฐ์ฒด๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ํ•ด๋‹น ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์ž๋™์œผ๋กœ ๋ทฐ์— ์—…๋ฐ์ดํŠธ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

class DataModel: ObservableObject {
    @Published var name = "Some Name"
    @Published var isEnabled = false
}

struct MyView: View {
    @StateObject private var model = DataModel()

    var body: some View {
        Text(model.name)
        MySubView(model: model)
    }
}

struct MySubView: View {
    @ObservedObject var model: DataModel

    var body: some View {
        Toggle("Enabled", isOn: $model.isEnabled)
    }
}

@ObservedObject ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ SwiftUI ๋ทฐ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ObservableObject ์ธ์Šคํ„ด์Šค๋ฅผ ์ „๋‹ฌํ•˜๊ณ , ํ•ด๋‹น ๊ฐ์ฒด์˜ @Published ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ทฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋Š” ์ฃผ๋กœ StateObject๋ฅผ ์„œ๋ธŒ๋ทฐ๋กœ ์ „๋‹ฌํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์œ„์˜ ์˜ˆ์ œ๋Š” ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์„ ObservableObject๋กœ ์ •์˜ํ•˜๊ณ , ํ•ด๋‹น ๋ชจ๋ธ์„ ๋ทฐ์—์„œ StateObject๋กœ ์ธ์Šคํ„ด์Šคํ™”ํ•œ ๋‹ค์Œ, ์„œ๋ธŒ๋ทฐ์— ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด @ObservedObject ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์‚ฌ์šฉ์ž๊ฐ€ name์ด๋‚˜ isEnabled๊ฐ’์„ ์—…๋ฐ์ดํŠธ ํ•˜๋ฉด, DataModel๊ฐ์ฒด์˜ @Published ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ณ , ์ด๋ฅผ ์˜์กดํ•˜๊ณ  ์žˆ๋Š” MySubView๊ฐ€ ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธ ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ์„œ๋ธŒ๋ทฐ์—์„œ ๋ชจ๋ธ ํ”„๋กœํผํ‹ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์˜ˆ๋ฅผ ๋“ค์–ด ์œ„์˜ ์˜ˆ์ œ์—์„œ์ฒ˜๋Ÿผ ํ† ๊ธ€์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ๋ทฐ ๊ณ„์ธต ๊ตฌ์กฐ์— ์žˆ๋Š” ๊ด€์ฐฐ์ž๋“ค์—๊ฒŒ ์ „ํŒŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โญ๏ธ ์ •๋ฆฌ

  • @ObservedObject ์†์„ฑ์„ ์‚ฌ์šฉํ•  ๋•Œ, ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๋ทฐ์˜ ์ž…๋ ฅ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, ๊ฐ์ฒด๋ฅผ ๋ทฐ ๋‚ด๋ถ€์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋‹ค๋ฅธ ์†์„ฑ(@StateObject, @EnvironmentObject)๋“ค์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

  • ObservableObject ๊ฐ์ฒด๋ฅผ ๊ตฌ๋…ํ•˜๊ณ , ๊ฐ์ฒด์˜ @Published ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ทฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํ•˜์ง€๋งŒ @ObservedObject ์†์„ฑ์— ๊ธฐ๋ณธ๊ฐ’์ด๋‚˜ ์ดˆ๊ธฐ๊ฐ’์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์€ ๊ถŒ์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. โŒ

๋งŒ์•ฝ ๊ฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ฑฐ๋‚˜, ๋ทฐ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” @StateObject๋‚˜ @EnvironmentObject ๋“ฑ์˜ ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

  • ๋”ฐ๋ผ์„œ @ObservedObject ์†์„ฑ์€ ์ฃผ๋กœ ๋ทฐ ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜, ์™ธ๋ถ€์—์„œ ์ฃผ์ž…๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

  • ์ด๋ฅผ ํ†ตํ•ด SwiftUI์—์„œ ๋ฐ˜์‘์ ์ด๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



๐Ÿ’ก ObservableObject Protocol

SwiftUI์—์„œ ObservableObject ํ”„๋กœํ† ์ฝœ์€ ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ(observable) ๊ฐ์ฒด๋ฅผ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
ObservableObject๋ฅผ ์ค€์ˆ˜ํ•˜๋Š” ๊ฐ์ฒด๋Š” @Published ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ์†์„ฑ์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์•Œ๋ฆฌ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋‹ค๋ฅธ ๊ฐ์ฒด๋“ค์—๊ฒŒ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์•Œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ObservableObject๋ฅผ ์ค€์ˆ˜ํ•˜๋Š” ๊ฐ์ฒด๋Š” SwiftUI ์•ฑ์˜ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ชจ๋ธ(model) ๊ฐ์ฒด๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ๋ชจ๋ธ ๊ฐ์ฒด๋Š” ๋ทฐ(view)์™€ ๋ถ„๋ฆฌ๋˜์–ด, ๋ทฐ์— ํ‘œ์‹œ๋  ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์—…๋ฐ์ดํŠธํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ๋ณ„๋„๋กœ ๊ด€๋ฆฌํ•จ์œผ๋กœ์จ, SwiftUI๋Š” ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๋ทฐ๋ฅผ ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

class Counter: ObservableObject {
    @Published var count = 0
}

์œ„์˜ ์˜ˆ์‹œ์—์„œ, Counter ํด๋ž˜์Šค๋Š” ObservableObject ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๊ณ , count ์†์„ฑ์€ @Published ์†์„ฑ์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋ ‡๊ฒŒ ๊ตฌํ˜„๋œ Counter ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋Š” ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๋กœ ๋™์ž‘ํ•˜๋ฉฐ, ๋ทฐ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ’ก @EnvironmentObject

SwiftUI View์˜ ์ƒ์œ„ ๋ทฐ์—์„œ ์ƒ์„ฑ ๋ฐ ๊ด€๋ฆฌ๋˜๋Š” ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์™€ View์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
@EnvironmentObject๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด View์—์„œ ์ด์ „์— ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋ฅผ ๋‹ค์‹œ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ์ฝ”๋“œ๋ฅผ ๋”์šฑ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ Docs

์‚ฌ์ง„

@EnvironmentObject๋Š” ์ฃผ๋กœ SwiftUI ์•ฑ์˜ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ „์—ญ์ ์ธ ๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

@EnvironmentObject๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ํ•˜์œ„ ๋ทฐ์—์„œ ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์ „๋‹ฌํ•˜์ง€ ์•Š๊ณ ๋„ ์ƒ์œ„ ๋ทฐ์—์„œ ์ „๋‹ฌํ•œ ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@EnvironmentObject๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ธ ๊ฐ€์ง€ ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. ์ „์—ญ์ ์ธ ๊ฐ์ฒด๋ฅผ ์ •์˜ํ•˜๊ณ  ObservableObject ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋„๋ก ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค
  2. ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์•ฑ์˜ root view์—์„œ environmentObject modifier๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
  3. ํ•˜์œ„ ๋ทฐ์—์„œ @EnvironmentObject ์†์„ฑ์„ ์‚ฌ์šฉํ•ด ๋“ฑ๋ก๋œ ๊ฐ์ฒด์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.


โญ๏ธ ์ •๋ฆฌ

class UserData: ObservableObject {
    @Published var name = "John Doe"
}

struct ContentView: View {
    @EnvironmentObject var userData: UserData
    
    var body: some View {
        Text("Hello, \(userData.name)!")
    }
}

struct MyApp: App {
    let userData = UserData()

    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(userData)
        }
    }
}

์œ„์˜ ์˜ˆ์‹œ์—์„œ, UserData ํด๋ž˜์Šค๋Š” ObservableObject ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋„๋ก ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
ContentView ๋ทฐ์—์„œ๋Š” @EnvironmentObject ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ userData ๊ฐ์ฒด์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.
๋งˆ์ง€๋ง‰์œผ๋กœ, MyApp ์•ฑ์—์„œ๋Š” ContentView๋ฅผ environmentObject modifier๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ userData ๊ฐ์ฒด๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

  • @EnvironmentObject๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ทฐ์—์„œ๋Š” ํ•ด๋‹น ๊ฐ์ฒด์˜ ์†์„ฑ์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๋ทฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ฏ€๋กœ, ์ด๋ฅผ ํ†ตํ•ด ์ƒ์œ„ ๋ทฐ์—์„œ ๊ด€๋ฆฌ๋˜๋Š” ์ „์—ญ์ ์ธ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.