-
[Swift] SwiftUI 프로퍼티 래퍼 뿌시기 2: @Published 찍먹하기 (feat. ObservableObject)테크 2024. 3. 6. 21:28
하... 사실 앞의 @State랑 @Binding은 빌드업이었던 것임ㅠ
Observ... 어쩌고저쩌고만 봐도 머릿 속에 물음표만 생겼던 나 자신
더 이상 미룰 수 없다. (왕진지)
일단 ObservableObject 이 친구가 무엇인지 알아야할 것 같은 느낌이 강하게 들어서
이 친구부터 먼저 도장깨보도록 하겠음!!!
※ Combine을 모르는 사람들을 위한 글입니다... (왜냐? 제가 모르기 때문에 ㅎㅋ)
ObservableObject
protocol ObservableObject : AnyObject
- Combine을 사용하는 것으로 이벤트 방출(emit)이 가능 (무슨 소린지 모르겠어도 포기하지 말고 계속 읽어주세요!)
- 클래스에서만 사용 가능
- 일반적으로 ViewModel 구현 시 사용 (ViewModel이란 View가 필요한 데이터를 가지고 있는 Model)
- ObservableObject 프로토콜을 따르는 클래스로 만들어진 인스턴스를 구독한다면 이벤트 변경을 실시간 트래킹 가능
아래처럼 선언이 가능한데요!
class Counter: ObservableObject { var count: Int = 0 }
참고로 ObservableObject를 공부하다보면 Combine이라는 말이 계속 등장합니다...
근데 Combine이 뭐냐구요?ㅠ
나도 잘 모르기 때문에 나중에 종권님 블로그 보면서 공부해야할 듯...
일단 대애충 이야기 해보자면
값을 내보내는/방출하는 Publisher와 이를 수신하는 Subscriber가 있고
이를 통해서 비동기 처리를 할 수 있다는 겁니다.
이 모든 걸 가능하게 하는 Framework가 Combine이라는 것이죠.
어쨌든 이것만 기억해주시면 됩니다.
Subscriber들은 방출된 값/이벤트만 받아볼 수 있고
Publisher가 방출한 값/이벤트만 구독자가 받아볼 수 있음ObservableObject는 이벤트 방출이 가능하기 때문에 일종의 Publisher 역할을 하는 겁니다!
이를 Subscriber가 구독한다면 방출된 이벤트를 계속 트래킹할 수 있다는 것!!!
※ Subcriber가 되려면 @ObservedObject라는 프로퍼티 래퍼로 감싸줄 수 있습니다. (물론 다른 방법도 있음)
관련해서는 다음 시간에 좀 더 하도록 할게요...!
그런데 ObservableObject를 사용한다고 해서 이벤트 방출이 자동으로 되는 것은 아닙니다. (미쵸ㅠ)
어떻게 이벤트를 방출할 수 있느냐?
두 가지 방법이 있는데요.
첫번째는 objectWillChange.send()를 사용하는 것입니다.
objectWillChange.send()는 이벤트 변경을 Subscriber에게 알려주는 함수인데요.
아래 코드를 보면 increaseCounter()를 할 때마다 objectWillChange.send()를 호출하고 있습니다.
이 말은 즉슨 increaseCounter()가 수행되면 이벤트 변경 시그널을 Subscriber에게 주는 것입니다!
이를 구독하고 있는 PlayerView의 counter는 (@ObservedObject로 감싸진 애)
increaseCounter()가 호출될 때마다 이벤트 변경을 실시간으로 받게 되고
결과적으로 Text("\(counter.count)")의 값이 자동으로 변경됩니다. (View가 자동으로 업데이트됨!)
import SwiftUI class Counter: ObservableObject { var count: Int = 0 func increaseCounter() { count = count + 1 objectWillChange.send() // Emit event! } } struct PlayerView: View { @ObservedObject var counter = Counter() // Subscriber var body: some View { VStack { Button("Increase Counter") { counter.increaseCounter() } Text("\(counter.count)") } } }
만약 objectWillChange.send()를 사용하지 않는다면
View 입장에서는 counter의 이벤트 변경 시그널을 받지 못했기 때문에
View가 업데이트 되지 않습니다.
Publisher가 방출한 값이 없으니 Subscriber 입장에서는 어떠한 값들도 받아볼 수 없는 것이죠!
한 가지 주의해야할 점은 @ObservedObject 명시인데요.
만약 PlayerView의 counter를 @ObservedObject로 감싸지 않는다면
counter는 Subscriber가 아니게 되기 때문에
Publisher에서 objectWillChange.send()가 실행이 된다고 하더라도
counter는 이벤트 변경 시그널을 받지 못해서
Text("\(counter.count)")에서는 값 업데이트가 일어나지 않습니다.
Subscriber만 이벤트 변경을 받아볼 수 있다!!!
기억해주세요!!!
@Published
@propertyWrapper struct Published<Value>
두번째로 ObservableObject의 이벤트 방출을 하는 방법은 @Published를 사용하는 것입니다.
정리를 해보자면,
- 이벤트 방출 대상임 ← 누군가가 이 값을 구독한다면 변경을 계속 트래킹할 수 있음!
- 클래스 내부 프로퍼티에서만 사용이 가능함 (반드시 클래스여야 함!!!)
바로 예제 코드 들어갑니다!
아까와는 다르게 increaseCounter()에서 objectWillChange.send()를 호출하지 않습니다.
하지만 count라는 녀석을 @Published로 감싸줌으로써
이 녀석의 변경이 실시간으로 Subscriber에게 전달이 되는겁니다! (간!단!)
그.래.서.
PlayerView에서 Increase Counter 버튼을 누르게 되면
View는 자동으로 변경된 counter 값을 렌더링해줍니다.
import SwiftUI class Counter: ObservableObject { @Published var count: Int = 0 func increaseCounter() { count = count + 1 } } struct PlayerView: View { @ObservedObject var counter = Counter() var body: some View { VStack { Button("Increase Counter") { counter.increaseCounter() } Text("\(counter.count)") } } }
마찬가지로 Counter 모델에서 @Published를 없앤다면 이벤트 방출 대상이 없어지기 때문에
Increase Counter 버튼을 눌러도 Subscriber는 이벤트 방출 시그널을 받지 못해서
증가된 count는 View에 보이지 않습니다.
Subscriber들만 이벤트를 실시간으로 받아볼 수 있고
Publisher가 방출한 이벤트만 Subscriber들이 읽어볼 수 있는 것...
다시 한 번 꼭 기억해주세요!
@ObservedObject와 관련된 건 다음 시간에 다루도록 할게요!
Property Wrapper에 대해서 함께 공부하고 싶다면
#PropertyWrapper 태그로 들어가기!'테크' 카테고리의 다른 글
[Swift] SwiftUI 프로퍼티 래퍼 뿌시기 4: @EnvironmentObject (0) 2024.03.07 [Swift] SwiftUI 프로퍼티 래퍼 뿌시기 3: @ObservedObject와 @StateObject 차이 이해하기 (0) 2024.03.07 [Swift] SwiftUI 프로퍼티 래퍼 뿌시기 1: @State와 @Binding (0) 2024.03.06 [Swift] Foundation에서 제공하는 동기화를 위한 Lock에 대해서 알아보기 | NSLock | NSRecursiveLock | NSConditionLock | NSCondition | NSDistributedLock (1) 2023.10.25 [OS101] 쓰레드 (0) 2023.09.14