본문 바로가기

SwiftUI+Combine

[Combine] @State, @ObservableObject, @Binding, @Published, @ObservedObject 각각의 역할은?

@State

@State는 swift5.1부터 추가된 어노테이션이며, 이는 view의 상태값을 참조하여 값이변경될때마다 view상태를 파괴하고 자시 재참조해줌으로써 프로퍼티 값의 상태를 감지해주는 어노테이션입니다. 

 

하지만 토글 유무와같은 한정되는 용도로만 사용되기를 권장하고있는데요 그이유가 뷰안에서 서용하는 메모리공간 때문입니다.

 

만일 다른클래스로 참조하고싶다면 ObservableObject 프로토콜을 사용하면 손쉽게 사용가능합니다

 

@Binding

@Binding이란 view에 보여질 값을 바인딩하는 State와 비슷하지만 다른점은 여러개의 view가 동시에 State의값을 참조할 수가 있습니다

예를들어 코드로 설명해보겠습니다.

 

Struct TestView: View {
	@State var name: String = “쿼카”

	var body: some view {
		ChildView(childName: $name)
		Text(name)
	}
}

struct ChildView: View {
	@Binding var childName: String

	var body: some View {
		Button(“Change Name”)
		childName = “쿼카아들”
	}
}

 

위코드의 상황은 

  • TestView가 ChildView를 소유하고있습니다.
  • ChildView의 프로퍼티를 초기하는 childName프로퍼티에 name프로퍼티를 바인딩합니다.
  • ChildView의 버튼을 누르면 childName의 값이 쿼카아들로 변경됩니다.

 

이 3가지의 특징이 있는데 결국 childView가 변경되는 기능을 가지고 있는 간단한 코드입니다.

 

이상태에서 childView내에 버튼을 눌러서 childName의 값이 추가되면 어떤 변화가 일어날까요 ?

 

childName의 값만 변경되는것이아니라 부모의 TestView내에 있는 name프로퍼티까지 값이 “쿼카아들”로 변경되게됩니다.

 

왜그럴까요 ?

 

$이달러기반으로 값을 바인딩하는것 자체가 참조로 등록되기때문입니다.

class에서 배웠던 참조기반의 특징을 살펴보신적이 있으실겁니다. (이정도는 아시리라믿습니다^^) 혹시 모르신다면 하단의 내용을 참조하세요!

링크(class와 struct의 차이)

 

즉, @Binding은 다른 어딘가에 연결되어있는 값이기때문에 한쪽에서 변경되면 참조되고있는 프로퍼티 또한 다 같이 변경되는 것입니다!!

 

https://nsios.tistory.com/145 

 

@ObservedObject 

@ObservedObject 

이는 대부분 viewModel을 만들때 사용하는 프로퍼티 래퍼입니다.

이는 ObservableObject프로포콜을 준수하는 타입에 사용할 수 있습니다.

그리고 ObservableObject프로토콜을 준수하면 objectWillChange.send()라는 메서드를 사용하여 view를 다시그려줄 수 있는 기능이존재하지만

이를 계속 호출해야하는 번거로움이 발생하기때문에 자동으로 값이 변경될때마다 자동으로 방출해주는 @Published를 같이 사용해주는 편입니다.

 

정리하면(

  • 감시할 대상자의 class는 @ObservableObject를 준수한다.
  • 감시할 대상자 타입의 프로퍼티가 @ObservedObject를 준수한다.
  • 값이 변경되는걸 감지하여 방출하는 프로퍼티가 @Published를 준수한다.

 

https://nsios.tistory.com/120#:~:text=%EA%B0%90%EC%8B%9C%EB%8C%80%EC%83%81%20%ED%81%B4%EB%9E%98%EC%8A%A4%20%EB%B3%80%EC%88%98%EC%97%90%EB%8A%94%20%40ObservedObject%EB%A5%BC%20%EC%84%A0%EC%96%B8%ED%95%98%EA%B3%A0%20%EA%B7%B8%20%EB%B3%80%EC%88%98%EC%9D%98

 

# 여기서 잠깐!!

ObservableObject는 class에게만 사용가능한 프로토콜입니다.

하지만 SwiftUI에는 View가 class가아닌 struct입니다.

즉, 해당뷰에대한 참조를 가질 수 가 없습니다.

 

그래서 view의 값이 변경될떄마다 다시 그려줘야하는 것이죠.

 

그런데 이런 비용도 만만치않은데 이를 리스트중 하나의 값이 변경될때마다 ? 계속 그려줄까요 ?

 

그렇지는 않다고합니다. 비용떄문에 SwiftUI에서도 매번 그리는것을 최대한 피하게끔 시스템이 설계되었다고하네요

하나만 그리는거면 상관없겠지만 하나의 값을 위해 여러개 유기적으로 엮여있는 리스트의 뷰들을 그려준다고하면 비효율적일겁니다.

 

실질적으로 코드를 실행하는 부분은 비용이많이들지않지만 직접 View로 보여주기위해 그려지는비용이 비싸다고합니다.

그래서? 필요한것만 새로 그려주는 방식이라고 합니다.

SwiftUI의 view가 class 방식이아닌 struct의 방식인 이유라고 할 수 도 있을것같네욤

 

https://nsios.tistory.com/145