ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [iOS/Swift] @StateObject vs @ObservedObject
    야매 iOS 2023. 8. 7. 06:42

    @StateObject와 @ObservedObject 모두 관찰하고 있는 객체에 변경이 생기면 이의 응답으로 SwiftUI 뷰를 갱신하게 한다.

    @StateObject와 @ObservedObject 모두 ObservableObject를 준수하는 인스턴스만 감시할 수 있다.

    • ObservableObject는 해당 인스턴스의 @Published 프로퍼티 값이 갱신되기 전에 변경된 값을 방출한다.
    • 이때 뷰가 다시 그려진다.
    class TempObservableObject: ObservableObject {
        @Published var name: String
    
        func changeName(to name: String) {
                    // 이때 암시적으로 objectWillChange.send가 호출된다
            self.name = name
        }
    }

    StateObject와 ObservedObject의 차이?

    1. 뷰가 재생성할 때 감시중인 인스턴스 또한 재생성되는가의 차이

    @ObservedObject

    @ObservedObject property wrapper로 감시하고 있는 인스턴스는 뷰가 새로 그려질 때마다 재생성된다.

    • 예를 들어 부모 뷰가 있고 자식 뷰가 있다. 그리고 자식 뷰는 @ObservedObject property wrapper로 갖는다.
    • 이때 부모 뷰는 @State, @StateObject, @ObservedObject 프로퍼티의 값이 변경되었을 때 부모 뷰가 다시 그려진다.
      • 부모 뷰에 포함되어 있는 자식 뷰도 다시 그려진다.
    • 자식 뷰가 다시 그려지면서 자식 뷰가 갖고 있는 @ObservedObject 또한 재생성되며 이전의 상태값이 유실된다.

    @StateObject

    property wrapper로 감시하고 있는 인스턴스는 뷰는 처음 뷰가 생성될 때만 초기화된다.

    • 다른 외부 요인에 영향을 받지 않고 뷰 자체의 상태를 가진다라고 유추할 수 있다

    1. 생성할 때의 차이

    @ObservedObject

    일반적으로 어느 인스턴스를 생성할 때 생성자로 필요한 매개변수를 넘겨줄 수 있다.

    이와 같이 자식뷰가 @ObservedObject 프로퍼티를 갖고 있고 부모뷰가 자식뷰를 생성할 때 해당 인스턴스를 주입해줄 수 있다.

    @StateObject

    StateObject는 ObservedObject의 케이스와 다르게 부모뷰가 자식뷰를 생성할 때 해당 인스턴스를 주입할 수 없다.

    필요한 값들을 생성자를 통해 넘겨주고 자식 뷰에서 그 값을 조합해 StateObject를 생성해야 한다.

    class NameModel: ObservableObject {
        @Published var name: String
    }
    struct MyView: View {
        @StateObject private var model: NameModel
    
        init(name: Stiring) {
            _model = StateObject(wrappedValue: { NameModel(name: name) }())
        }
    }
    
    struct ContentView: View {
        @State name: String = "name"
    
        var body: some View {
            MyView(name: name)
        }
    }

    위와 같은 방식을 사용해 직접 StateObject를 생성했다면 ContentView에서 name이 변경되었을 때 그 변경된 값을 MyView는 전달받지 못한다.

    • StateObject는 뷰가 처음 생성될 때만 초기화되기 때문

    하지만 StateObject를 강제로 다시 초기화하게끔 할 수 있다.

    • 뷰의 identity를 같이 변경시키면 된다.

    하나의 값이 변경되었을 때 다시 초기화 하는 방법

    var body: some View {
        MyView(name: name)
            .id(name)
    }

    두 개 이상의 값이 변경되었을 때 다시 초기화 하는 방법

    var hash: Int {
        var hasher = Hasher()
        hasher.combine(name)
        haser.combine(number)
        return hasher.finalize()
    }
    
    var body: some View {
        MyView(name: name)
            .id(hasher)
    }

    왜?

    왜 StateObject는 ObservableObject를 넘겨 받을 수 없을까라는 생각을 했다.

    • 첫 번째 차이점으로 StateObject는 다른 외부 요인에 영향을 받지 않고 뷰 자체의 상태를 가지는 것을 알 수 있었다.
    • ObservableObject는 기본적으로 class-bound를 가진다. 그러므로 call by value가 아닌 call by reference란 것을 알 수 있다
      • reference로 전달하므로 상위 뷰에서의 변경이 자식뷰에도 영향을 있다.
      • 그래서 @StateObject에게 인스턴스를 넘겨주는 것이 막혀 있지 않을까라는 생각이 든다.

    '야매 iOS' 카테고리의 다른 글

    [Swift] some & any  (0) 2023.08.07
    [Swift] Protocol Oriented Programming  (0) 2023.08.07
    [iOS/Swift] Operation  (0) 2023.08.06
    [iOS/Swift] 동시성 문제  (0) 2023.08.06
    [iOS/Swift] DispatchGroup / Dispatch Work Item  (0) 2023.08.06
Designed by Tistory.