iOS ๐ŸŽ/Property wrapper

[iOS/SwiftUI] @Published, ObservableObject, ObservedObject

fram 2023. 4. 3. 16:17
  • ํ•˜๋‚˜์˜ ๋ทฐ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ @State, Child View ํ˜น์€ ๋‹ค๋ฅธ View์™€์˜ ์–‘๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์—์„œ ์‚ฌ์šฉํ•˜๋Š” @Binding๊ณผ ๋‹ฌ๋ฆฌ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ๊ณผ ๋ทฐ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์œ„ํ•ด ์‚ฌ์šฉ๋จ
  • ์•ฑ์˜ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ๊ณผ ๋ทฐ ์‚ฌ์ด์˜ ์—ฐ๊ฒฐ ์ƒ์„ฑ
  • view (x), viewModel๊ณผ ๊ฐ™์€ model ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํ”„๋กœํ† ์ฝœ๊ณผ propertyWrapper

 

OverView

  • ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์€ UI์™€ ๋‹ค๋ฅธ ๋กœ์ง๋“ค๊ณผ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์Œ (๋ชจ๋“ˆํ™”, testable) -> ์•ฑ ์ž‘๋™ ์ถ”๋ก ์ด ๋” ์‰ฌ์›Œ์ง
  • UIViewController์„ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” ๋ชจ๋ธ์˜ ๊ฐ’์„ ViewController๋กœ ๊ฐ€์ง€๊ณ  ์™€์„œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ํ™”๋ฉด์— ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ๋กœ์ง์„ ํ•„์š”๋กœ ํ–ˆ์œผ๋‚˜ SwiftUI์—์„œ ์‹œ์Šคํ…œ์ด ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•˜๊ณ  ์ด๋ฅผ UI์— ๋ฐ”๋กœ ๋ฐ˜์˜ํ•จ
  • ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์‹œ view๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋ ค๋ฉด model ํด๋ž˜์Šค๋ฅผ ObservableObejct๋กœ ์ƒ์„ฑ,  model ํด๋ž˜์Šค์˜ properties๋ฅผ publish ํ•œ ๋‹ค์Œ @ObservedObject ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•ด๋‹น model ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉ

ObservableObject Protocol

  • ๋ชจ๋ธ์˜ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ SwiftUI์— ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด ObservableObject ํ”„๋กœํ† ์ฝœ์„ ๋ชจ๋ธ ํด๋ž˜์Šค์— ์ฑ„ํƒํ•ด ์คŒ
    • ๋ง๊ทธ๋Œ€๋กœ Observable ์˜ต์ €๋น™ ๊ฐ€๋Šฅํ•œ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ. ์ด ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋ฉด ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๋ฅผ subscriber๊ฐ€ ๊ตฌ๋…ํ•˜์—ฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ด๋ฒคํŠธ ๋ฐฉ์ถœ ๊ฐ€๋Šฅ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋จ
class BooK: ObservableObject {
    @Published var title = "๋™๋ฌผ๋†์žฅ"
}

 

Published

  • Observing ํ•˜๊ธฐ ์œ„ํ•œ property๋ฅผ ๊ฒŒ์‹œํ•˜๊ธฐ ์œ„ํ•ด @Published Property Wrapper์„ ์‚ฌ์šฉํ•˜์—ฌ ์ •์˜ํ•ด ์คŒ
  • ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” didSet์—์„œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐฉ์ถœํ•จ
  • ์ฃผ์˜์‚ฌํ•ญ
    • ํ•„์š”ํ•˜์ง€ ์•Š์€ ์†์„ฑ์„ Published๋กœ ์ •์˜ํ•ด์„œ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์•ผ ํ•จ
    • ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š”์ง€, ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์— ์‚ฌ์šฉ๋˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์ •์˜ํ•˜๋„๋ก ํ•จ
class Library: ObservableObject {
    let idx = UUID()
    let name: String
    @Published var books: [Book]
    
    init(name: String, books: [Book]) {
        self.name = name
        self.books = books
    }
}
  • Library ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด ์‹œ์Šคํ…œ์€ idx์™€ name์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๋Š” ๊ฒƒ์„ ํ™•์‹ ํ•˜๊ณ , books๋Š” published ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๊ฐ’์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๊ฐ์‹œํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋จ. ๋”ฐ๋ผ์„œ @Published๋กœ ์ •์˜๋œ ํ”„๋กœํผํ‹ฐ๋Š” var๋กœ ์„ ์–ธ

ObservedObject

  • ObservableObject๋Š” protocol, ObservedObject๋Š” propertyWrapper
  • ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ชจ๋‹ˆํ„ฐ๋ง ํ•จ
  • SwiftUI์—๊ฒŒ Observable object๋ฅผ ๊ฐ์‹œํ•˜๋ผ๊ณ  ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ObservedObject ์†์„ฑ์œผ๋กœ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ •์˜ํ•จ
struct BookView: View {
    @ObservedObject var book: Book
    
    var body: some View {
        BookEditView(book: book)
    }
}

struct BookEditView: View {
    @ObservedObject var book: Book

    // ...
}
  • ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด SwiftUI ์‹œ์Šคํ…œ์€ ๊ด€๋ จ๋œ ๋ชจ๋“  ๋ทฐ์—๊ฒŒ ์—…๋ฐ์ดํŠธ๋ฅผ ์š”์ฒญํ•จ
  • ์œ„ ์˜ˆ์ œ๋ฅผ ํ™•์ธํ•˜๋ฉด BookEditView๋ผ๋Š” ์ž์‹ ๋ทฐ์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š”๋ฐ, Observable Object ์ „์ฒด๋ฅผ ์ž์‹ ๋ทฐ์—๊ฒŒ ์ „๋‹ฌ ๊ฐ€๋Šฅํ•จ (๋ทฐ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ€๋กœ์งˆ๋Ÿฌ ๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ๊ณต์œ ๊ฐ€๋Šฅ)
  • ObservedObject๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ๊ฒฝ์šฐ ObservableObject๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ
  • ObservableObject๊ฐ€ ์™ธ๋ถ€๊ฐ€ ์•„๋‹Œ ๋‚ด๋ถ€์—์„œ ์ „๋‹ฌํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋ผ๋ฉด ํ™”๋ฉด์„ ๋‹ค์‹œ ๊ทธ๋ฆด ๋•Œ ์ดˆ๊ธฐํ™” ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฏ€๋กœ ์ด ๋•Œ์—๋Š” StateObject ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ•จ

Binding์„ ์‚ฌ์šฉํ•ด์„œ ์–‘๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ Passing

  • UI์—์„œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›๊ณ  ์ด ๊ฐ’์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ์ด์— ์ƒ์‘ํ•˜๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ฐ”์ธ๋”ฉ ํ•ด์ค˜์•ผ ํ•จ
  • ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ viewModel์— ์—…๋ฐ์ดํŠธ ํ•  ์ˆ˜ ์žˆ์Œ
  • ObservedObject, StateObject, EnvironmentObject ํ”„๋กœํผํ‹ฐ๋Š” ๊ทธ ๊ฐ์ฒด ์•ž์— ๋‹ฌ๋Ÿฌ์‚ฌ์ธ์„ ๋ถ™์—ฌ์„œ ๋ฐ”์ธ๋”ฉ ํ•ด์ค„ ์ˆ˜ ์žˆ์Œ
  • ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ๋ฐ์ดํ„ฐ์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋„๋ก ํ—ˆ์šฉํ•˜๊ฒŒ ๋จ
struct BookEditView: View {
    @ObservedObject var book: Book
    
    var body: some View {
        TextField("Title", text: $book.title)
    }
}