SwiftUI Property Wrappers - @StateObject

sanghoon Ahn·2023년 2월 18일
0

SwiftUI

목록 보기
3/5

Observable object를 instance화 시키는 property wrapper

@State와 비슷한 이유로 사용되지만 ObservableObjects로 사용되길 기대할 때 사용합니다.

@StateObject property는 ObservableObject protocol을 따르는 initial value가 필요합니다.

SwiftUI는 structure의 각 인스턴스에 대해 한 번만 객체의 새 인스턴스를 만듭니다.

또한 property의 observable object가 변경될 때 SwiftUI는 property에 의존된 view를 업데이트합니다.

@ObservedObject attribute를 가진 state object는 property로 전달될 수 있으며 environmentObject(:_) modifier를 통해 view hierarchy envrionment에 새로운 object를 추가 할 수 있습니다.

ContentView().environmentObject(model)

위 코드 처럼 environment object를 생성하고, model이 아래와 같은 @EnvironmentObject property wrapper를 가지고 있다면

@EnvironmentObject var model: DataModel

ContentView의 object에 read 접근이 가능합니다.

ObservableObject는 항상 참조타입이며, @Published 속성 중 하나가 변경될 때마다 SwiftUI에 알립니다.

class DataProvider: ObservableObject {
    @Published var currentValue = "a value"
}

struct DataOwnerView: View {
    @StateObject private var provider = DataProvider()
    
    var body: some View {
        Text("provider value: \(provider.currentValue)")
    }
}

DataOwnerView가 DataProvider의 instance를 생성하고, currentValue가 변경될 때 DataOwnerView가 리렌더링됩니다.

SwiftUI는 내부적으로 생성된 DataProvider의 instance를 DataOwnerView가 리랜더링을 위해 버려지거나 재생성될때 처음 생성한 instance를 유지합니다.

이는 @StateObject가 주어진 뷰에 대해 단 한번만 초기화됨을 의미합니다.

SwiftUI는 @StateObject와 관련된 인스턴스를 따로 설정하고 @StateObject를 소유한 뷰가 다시 초기화될 때 재사용합니다.

이것은 새 뷰 인스턴스가 재사용되었기 때문에 @StateObject로 표시된 속성의 새 인스턴스를 얻지 못한다는 것을 의미하며 @StateObject로 표시된 속성은 구조가 SwiftUI에 의해 재창조되는 경우에도 뷰가 필요한 한 처음에 할당된 ObservedObject 인스턴스를 유지합니다.

@State와 비슷한 동작이지만 value 타입이 아닌ObservableObject에만 적용되는 점을 제외하면 동일합니다.

@StateObject을 사용해야하는 경우는

  • ObservableObject의 변화에 따라 처리해야는 일이 있을 때
  • view가 @StateObject를 사용하고 ObservableObject를 스스로 생성할 때 사용합니다

Observable Object란?

객체가 변경되기전에 이벤트를 방출하는 타입

기본적으로 ObservableObject는 @Published 속성이 변경되기 전에 변경된 값을 objectWillChange 에서 방출합니다.

objectWillChange는 ObjectWillChangePublisher 타입의 instance property이며 아래와 같이 사용할수있습니다.

class Contact: ObservableObject {
    @Published var name: String
    @Published var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    func haveBirthday() -> Int {
        age += 1
        return age
    }
}

let john = Contact(name: "John Appleseed", age: 24)
cancellable = john.objectWillChange
    .sink { _ in
        print("\(john.age) will change")
}
print(john.haveBirthday())
// Prints "24 will change"
// Prints "25"

ObjectWillChangePublisher는 연관 타입이며 정의는 아래와 같습니다.

associatedtype ObjectWillChangePublisher : Publisher = ObservableObjectPublisher where Self.ObjectWillChangePublisher.Failure == Never

ObjectWillChangePublisher는 Publisher 타입이며

여기서 ObservableObjectPublisher는 class 이고 Publisher protocol을 준수합니다.

profile
hello, iOS

0개의 댓글