본문 바로가기
TIL (Today I Learned)

ObservableObject , @ObservedObject, @StateObject

by Bokoo14 2024. 1. 21.

[참고]

더보기

 

import SwiftUI

class MyData: ObservableObject {
    @Published var count: Int = 0
}

struct ContentView: View {
    @StateObject var data = MyData()
    // @ObservedObject var data = MyData()
    
    var body: some View {
        VStack {
            Text("Count: \(data.count)")
            Button("Increment") {
                data.count += 1
            }
        }
    }
}

 

📝 ObservableObejct?

ObservableObject는 SwiftUI에서 상태를 관리하고 업데이트하는 데 사용되는 프로토콜입니다.

이 프로토콜은 객체의 값이 바뀌기 전에 알려주는 퍼블리셔를 의미하며, SwiftUI가 화면을 다시 그리는 것을 가능하게 함.

 

이 프로토콜은 클래스에서만 구현할 수 있다. 그 이유는 ObservableObject가 객체의 상태 변화를 추적하고 업데이트하기 위해 참조 타입인 클래스의 특징을 이용하기 때문임

  • ObservableObject는 @Published 속성 래퍼를 사용하여 속성의 변경 사항을 자동으로 게시(publish)하고, SwiftUI 뷰가 이러한 변경 사항을 감지하여 업데이트할 수 있게 합니다. 이를 통해 상태의 변화를 통지하고, 뷰가 이를 반영하여 사용자 인터페이스를 업데이트할 수 있음
  • ObservableObject는 class 형태만 가능 (구조체(struct)는 값 타입이므로 ObservableObject 프로토콜을 직접 구현할 수 없다. 구조체는 값 복사(copy)의 특성을 가지기 때문에 참조 타입인 클래스처럼 변경 사항을 추적하고 공유할 수 없음)
  • @Published 변화했다는 신호를 쏴서 다른 부분에서 변화를 알게 한다.(@Published 프로퍼티는 모든 관찰자가 변경된 신호를 수신하도록 함)

📝 @ObservedObejct?

  • Observable 객체를 구독하는 property wrapper
    • Observable 객체가 변경되면 뷰에 업데이트 시켜주는 기능
    • ObservableObject를 준수하는 모델을 만들고, 그 모델에서 값이 변경되면 뷰에 반영하기 위함
    • ObservableObejct를 준수하는 인스턴스를 참조하기 위해서 @ObservedObject로 선언하여 참조
    • ObservedObject는 View가 새로 그려질때 새로 생성될 수 있음 (View의 라이프사이클에 의존)

📝 @StateObject?

  • @StateObject를 통해서 관찰되고 있는 객체는 그들을 가지고 있는 화면 구조가 재생성되어도 파괴되지 않음
  • StateObject는 View가 새로 그려질때 State처럼 새로 그려지지않고 참조를 가지고 있어서 새로 생성되지 않음 (View의 라이프사이클에 의존하지 않음)

 

📝 @ObjervedObject vs @StateObject

공통점 차이점
 - ObservableObject를 구독하여, 이 값이 변경되면 뷰에 반영해주는 property wrapper 형태 - 상태 변경이 있을땐 @ObjervedObject는 뷰를 다시 생성해서 그리지만, @StateObject는 뷰를 다시 생성하지 않고 항상 동일한 뷰를 사용 (효율)

- 기본적으로 @StateObject를 사용하되, 해당 프로퍼티를 subview에게도 주입시켜야 한다면, @ObservedObject로 선언하여 사용할 것

- subview에 @StateObject 프로퍼티를 주입하면, 해당 @StateObject의 수명 주기가 두 곳에서 관리가 되므로 의존성을 줄이기 위해 @ObservedObejct를 사용

 

💡 부모 뷰에서 상태값이 업데이트 되어 뷰가 다시 그려질때, ObservableObject를 구독하고 있는 subview의 상태값이 초기화 되는지 유무

  • @ObservedObject: 뷰가 다시 생성되어, 상태값들이 초기화 되는 것을 확인
  • @StateObject: 뷰가 다시 생성되지 않아서, 상태값들이 초기화 되지 않는 것을 확인

💡 언제 @StateObject를 써야 할까?

SwiftUI가 화면을 만들거나 다시 그릴 수 있는 가능성이 있는 경우엔 내부에@ObservedObject를 쓰는 것은 안전하지 않음.

@ObservedObject 객체를 외부에서 주입하는 것이 아니라면 @StateObject를 사용하는 것이 화면이 다시 그려져도 항상 같은 결과를 얻을 수 있을 것이다. 

💡 그럼 항상 @StateObject를 쓰면 좋지 않을까?

아니다.

동일한 @StateObject 인스턴스를 관찰하고 있는 자식들은 객체를 프로퍼티 래퍼로 표시할 필요가 없음.

그렇게 되면 여러군데에서 객체의 라이프사이클을 관리하게 돼서 그러지 않는 것이 좋다.

@StateObject 사용하면 해당 객체의 상태를 추적하고 업데이트하기 위해 추가적인 메모리 연산이 필요하다. 따라서, 단순히 상태를 표시할 필요가 없는 경우에는 @StateObject 사용하지 않는 것이 좋습니다.

 

@StateObject @ObservedObject
- 뷰와 관련된 객체를 만들고 관리하는 데 사용됨

- 동일한 객체를 여러 뷰에서 공유해야 할 때 사용

- 하나의 객체 인스턴스를 여러 뷰가 공유하면 해당 객체의 상태가 모든 뷰에서 동일하게 유지됨

- 뷰가 객체를 생성하고 해당 객체를 소유하며 라이프사이클을 관리합니다. (동일한 뷰 계층 내에서는 동일한 @StateObject 인스턴스를 사용)

- 뷰가 객체를 생성하고 해당 객체를 소유하며 라이프사이클을 관리

- 예를 들어, 여러 뷰에서 공유하는 사용자 설정을 관리하는 경우 @StateObject를 사용할 수 있습니다.
- @ObservedObject는 뷰가 외부에서 제공된 객체를 관찰하고 해당 객체의 변경 사항을 반영하는 데 사용됨

- 다른 뷰나 뷰 모델이 생성한 객체를 현재 뷰에서 사용하고 싶을 때 @ObservedObject를 사용한다. 현재 뷰는 해당 객체의 상태를 관찰만 하고 소유하지 않음

- 다른 뷰나 뷰 모델이 생성한 객체를 현재 뷰에서 사용하고 싶을 때 @ObservedObject를 사용

- 현재 뷰는 해당 객체의 상태를 관찰만 하고 소유하지 않습니다.

- 예를 들어, 상위 뷰에서 생성한 뷰 모델을 하위 뷰에서 사용하고 해당 뷰 모델의 변경 사항을 반영하려면 @ObservedObject를 사용할 수 있다

 

📝  @EnvironmentObject?

  • 앱이 살아있는 한, 계속 메모리에 존재하는 퍼블리셔
  • 전체 앱의 생명주기에서 계속 필요한 정보, 그리고 모든 뷰에서 필요한 정보를 갖고 있게 하면 된다.
  • 최상위에 선언해주면 전역 변수로 사용할 수 있음
  • 모든 뷰가 사용해야하는 상태변수가 필요할 때 유용하다.
  • SwiftUI 환경(메모리)에 저장되며 뷰에서 뷰로 참조체를 전달할 필요 없이 부모 뷰의 모든 하위 뷰에서 접근에 가능하다. (싱글톤 처럼 하나의 객체가 메모리에 생성되어 사용할 수 있게 되는 것이다.)

 

 

📝  결론

  • 동일한 객체를 여러 뷰에서 공유해야 할 경우 @StateObject를 사용하고, 다른 뷰에서 생성한 객체를 현재 뷰에서 사용하고 관찰해야 할 경우 @ObservedObject를 사용하자.
  • @ObservedObject를 종속성으로 주입하지 않는 한, 뷰를 다시 그린 후 일관된 결과를 보장하기 위해 @StateObject 래퍼를 사용하는게 좋다
  • @StateObject는 개체의 수명 주기를 유지하고 관리하도록 요청할 것이므로, 필요한 경우에만 써야 객체의 라이프사이클을 적절하게 관리하고 데이터 흐름을 효과적으로 구성할 수 있다.
  • 관찰된 개체를 주입하는 경우라면 @ObservedObject를 사용해야 한다.

 

'TIL (Today I Learned)' 카테고리의 다른 글

[Swift] 메모리 관리  (1) 2024.02.08
[SwiftUI] SwiftUI의 View란?  (0) 2024.01.30
[iOS] NearbyInteraction란?  (2) 2024.01.13
[macOS] 샌드박스란?  (3) 2024.01.13
[SwiftUI] SwiftUI 기본 컴포넌트 정리  (0) 2023.03.24