[SwiftUI] StateObject VS ObservedObject

마이노·2022년 12월 31일
0
post-thumbnail

SwiftUI를 사용하다 보면 ObservableObject를 채택해 모델의 데이터 변경사항을 구독할 때가 있다. 어떤 상황에서 쓰는지 두개의 특성을 비교해 보도록 한다.

@ObservedObject

뷰가 인스턴스를 생성하면 뷰가 삭제되고 다시 그려질 때마다 생성된다.

이해를 돕기 위해 간단한 코드를 작성하고 살펴보도록 한다.

class DataSource: ObservableObject {
  @Published var counter = 0
}

struct Counter: View {
    @ObservedObject var dataSource = DataSource()

  var body: some View {
    VStack {
      Button("Increment counter") {
        dataSource.counter += 1
      }

      Text("Count is \(dataSource.counter)")
    }
  }
}

struct ItemList: View {
  @State private var items = ["hello", "world"]

  var body: some View {
    VStack {
      Button("Append item to list") {
        items.append("test")
      }

      List(items, id: \.self) { name in
        Text(name)
      }

      Counter()
    }
  }
}

배열을 보여주는 리스트가 있고, 배열을 추가시킬 수 있으며 하단에는 카운터를 증가시키는 텍스트를 배치하였다.

여기서 ObservedObject의 특성이 드러나는데
배열추가버튼을 누르면 카운터가 0으로 초기화된다. 초기화 -> 인스턴스가 유지되지 않고 초기화가 되는것. 즉 뷰를 다시그리는 작업을 하게 된다.

그런데 만약 배열에 추가를 하고 증가한 카운터의 숫자도 유지하고 싶다면 StateObject를 사용해야 한다. 인스턴스가 유지되고 재사용 되기 때문이다.

@StateObject

뷰가 삭제되고 다시 그려진 후에도 인스턴스가 유지되고 재사용된다.

StateObject는 ObservedObject와 거의 동일한 방식으로 작동하지만 둘 사이의 가장 큰 차이점은 소유권이다. StateObject 객체를 생성하는 뷰는 데이터 소유자. 따라서 해당 개체의 변경사항을 보고 싶다면 @ObservedObject를 사용하여 확인한다. 다만 확인은 가능하되 소유는 불가능 한 것

이제 둘의 차이점을 알게 되었다. 올바르게 코드를 작성하는 법은 무엇일까?

struct LibraryView: View {
    @StateObject private var book = Book()
    
    var body: some View {
        BookView(book: book)
    }
}

객체를 최초의 뷰(LibraryView)에서 한번 생성하고 값을 넘긴다.
그렇다면 BookView에서는? @ObservedObject로 받으면 되는 것

앱 전체에서 개체를 공유하려고 할 때에도

@main
struct BookReader: App {
    @StateObject private var library = Library()
    
    var body: some Scene {
        WindowGroup {
            LibraryView()
                .environmentObject(library)
        }
    }
}

struct LibraryView: View {
    @EnvironmentObject var library: Library
    
    // ...
}

a -> b -> c로 데이터의 흐름이 있다고 가정하자.
a(StateObject) -> b(observedObject) -> c(observedObject)
로 데이터를 받아야 하는 것은 꽤나 불편한 작업일 것이다. 따라서 환경에 배치하여 모든 하위 뷰에서는 속성을 사용해 인스턴스에 접근할 수 있을 것이다.

참고자료
1.https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
2.https://stackoverflow.com/questions/62544115/what-is-the-difference-between-observedobject-and-stateobject-in-swiftui
3.https://www.hackingwithswift.com/quick-start/swiftui/whats-the-difference-between-observedobject-state-and-environmentobject
4.https://www.donnywals.com/whats-the-difference-between-stateobject-and-observedobject/

profile
아요쓰 정벅하기🐥

0개의 댓글