@PropertyWrapper - ObservableObject, EnvironmentObject (수정중..)

2023. 11. 12. 00:39Mobile/SwiftUI

이전에 살펴보았던, State 프로퍼티는 뷰의 상태를 저장하는 방법을 제공하며 해당 뷰에만 사용할 수 있다.

즉, 하위뷰가 아니거나 State Binding 이 구현되어 있지 않은 다른 뷰는 접근할 수 없다. 상태 프로퍼티는 일시적인 것이어서 부모 뷰가 사라지면 그 상태도 사라진다.

ObservableObject

Observable 객체는 여러 다른 뷰들이 외부에서 접근 할 수 있는 지속적인 데이터를 표현하기 위해 사용된다.

→ 객체가 변경되기 전에 내보내는 publisher(게시자) 가 있는 객체 유형

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())

 

ObservableObject 타입의 클래스 Contact 에 게시자 name, age 를 지정하고, 생성해준다. 그 외 인스턴스 메소드인 haveBirthDay 에 나이에 += 1을 해주는 함수를 지정해주고, objectWillChange 를 써서 john 이라는 이름의 String 타입에 접근해서 john.age 를 변경시켜주고, john 의 나이를 추가해주는 메소드 호출을 프린트하면 나이가 25가 되어 있을것이다.

 

Observable 객체는,

  • ObservableObject 프로토콜을 따르는 클래스구조체 형태를 취한다.
  • Observable 객체는 일반적으로는 시간에 따라 변경되는 하나 이상의 데이터 값을 모으고 관리하는 역할을 담당한다.
  • 타이머나 알림(notification) 과 같은 이벤트를 처리하기 위해 사용할 수도 있다.
  • Observable 객체는 게시된 프로퍼티published property로서 데이터 값을 게시한다.
  • Observable 객체는 게시자를 구독하여 게시된 프로퍼티가 변경될 때마다 업데이트를 받는다.
  • Combine 프레임워크에 포함되어 있는 Observable 객체는 Publisher, Subscriber 관계를 쉽게 구축할 수 있도록 iOS 13 + 에 도입됨.
Combine
여러 게시자를 하나의 스트림으로 병합하는 것부터 게시된 데이터를 구독자의 요구에 맞게 변형하는 것까지 다양한 작업을 수행하는 커스텀 게시자 구축 플랫폼을 제공함. 또한, 최초 게시자(Publisher)와 최종 구독자(Subscriber) 간에 복잡한 수준의 연쇄 데이터 처리 작업도 구현할 수 있다. 하지만, 일반적으로는 내장된 게시자 타입들 중 하나면 충분할 것이다. 실제로 Observable 객체의 게시된 프로퍼티를 구현하는 가장 쉬운 방법은 프로퍼티를 선언할 때
@Published
프로퍼티 래퍼를 사용하는 것이다. 이 래퍼는 래퍼 프로퍼티 값이 변경될 때마다 모든 구독자에게 업데이트를 알린다.

 

import Foundation
import Combine

class TimerData: ObservableObject {
	@Published var timeCount = 0
	var timer: Timer?
	
	init() {
		timer = Timer.scheduledTimer(
                              timeInterval: 1.0,
                              target: self,
                              selector: #selector(timerDidFire),
                              userInfo: nil,
                              repeats: true)
	}
	
	@objc func timerDidFire() {
		timeCount += 1
	}
	
	func resetCount() {
		timeCount = 0
	}
}

timeCount 변수를 @Published(게시자) 타입으로 초깃값 0 으로 설정

 

EnvironmentObject

structure

상위 또는 조상 뷰가 제공하는 관찰 가능한 객체에 대한 프로퍼티 래퍼 유형

@frozen @propertyWrapper
struct EnvironmentObject<ObjectType> where ObjectType : ObservableObject

Environment 객체는 Observable 객체와 같은 방식으로 선언된다. 즉, 반드시 ObservableObject 프로토콜을 따라야 하며, 적절한 프로퍼티가 게시되어야 한다.

중요한 차이점은 이 객체는 SwiftUI 환경에 저장되며, 뷰에서 뷰로 전달할 필요 없이 모든 자식 뷰가 접근할 수 있다는 것이다.

 

Environment 객체는 ObservableObject 를 준수하는 관찰 가능한 객체가 변경될 때마다 현재 view를 무효화(invalidate)한다. 속성을 Environment Object 로 선언하는 경우, 해당 모델 객체의 EnvironmentObject(_:) 수정자를 호출해 조상 뷰에 해당 모델 객체를 설정해야함.

 

environmentObject(_:)

뷰의 계층 구조에 관찰 가능한 객체를 제공한다.

func environmentObject<T>(_ object: T) -> some View where T : ObservableObject

Parameter

뷰의 계층 구조에 저장하고 사용할 수 있는 객체

Discuss

이 수정자를 사용해 관찰 가능한 개체를 보기 환경에 추가한다. 객체는 ObservableObject 프로토콜을 준수해야한다. 뷰 환경에 객체를 추가하면 뷰 계층의 하위 뷰에서 해당 객체를 사용할 수 있다. 하위 뷰에서 객체를 검색하려면 EnvironmentObject 속성 래퍼를 사용

 

 


수정중...

 

참고: 핵심만 배우는 SwiftUI 기반의 프로그래밍 

https://developer.apple.com/documentation/swiftui/environmentobject