맛동산이

SwiftUI) TAC 에서 공유 데이터 사용하는법(shared Data), AsyncStream과 Shared State 본문

앱/SwiftUI

SwiftUI) TAC 에서 공유 데이터 사용하는법(shared Data), AsyncStream과 Shared State

진ddang 2024. 9. 17. 04:39

예를 들어서, 로그인 상태를 바라본다고 했을때

로그인 상태는 앱이 시작됨과 동시에 계속해서 해당 값을 바라보고 있다가.

로그아웃이 될때 앱의 화면을 변경해줘야하는 상황이 발생한다.

이처럼 앱 전반적으로 해당 상태를 옵저빙 해야하는 경우가 발생하고 이를 해결할수 있는 방법이 크게

  • shared state
  • asyncStream

가 있다.

AsyncStream을 통한 공유 상태 처리하는 법

Shared data in a TCA app

1. Dependency 정의해주기

struct AuthenticationClient: Sendable {
    var currentUser: @Sendable () -> AppUser?
    var listenAuthState: @Sendable () async throws -> AsyncThrowingStream<AppUser?, Error>

    init(
        currentUser: @escaping @Sendable () -> AppUser?,
        listenAuthState: @escaping @Sendable () async throws -> AsyncThrowingStream<AppUser?, Error>,
    ) {
        self.currentUser = currentUser
        self.listenAuthState = listenAuthState
    }
}

이때 해당 클래스의 상태를 위에는 currentUser라는 값을 받도록 하였는데

이부분에 대해서는 @Published와 같은 프로퍼티 래퍼를 이용해도 가능하다.

2. Dependency내부에서 해당 값을 AsyncStream으로반환해주기

  1. 직접 반환해주는 방법(AsyncStream을 생성해서 )
  public static let liveValue = Self(
        currentUser: {
            let user = Auth.auth().currentUser
            return .init(from: user)
        },
         listenAuthState: {
            AsyncThrowingStream { continuation in
                let listenerHandle = Auth.auth()
                    .addStateDidChangeListener { auth, user in
                        if let user {
                            let appUser = AppUser(from: user)
                            continuation.yield(appUser)
                        } else {
                            continuation.yield(nil)
                        }
                    }

                continuation.onTermination = { _ in
                    Auth.auth().removeStateDidChangeListener(listenerHandle)
                }
            }
          }
        })

이런식으로 AsyncStream을 만들어서 반환해주면 된다.

3. 뷰에서 task로 연결해주기

.task {
    await viewStore.send(.view(.listenGroups)).finish()
}

를 통해서 위에서 만들어줬던 listenGroups를 연결해주면 끝

그러면 계속해서 해당 값을 바라보고 있는 상태가 된다.

이때 .fisish 는 cancellableValue로 스트림이 종료될수 있도록 변경해주는 역할을 한다.

  /// Waits for the task to finish.
  public func finish() async {
    await self.rawValue?.cancellableValue
  }

이러한 방법으로 shared data 를 계속해서 observing할수 있음

Shared Data

TCA - Shared State

Sharing state in the Composable Architecture

콤바인은 Reducer가 다양한 childReducer와 결합되어있는 상태이다.

이때 상위 Reduer에서 하위 Reducer와 상태를 공유 하고 싶을때 사용하는것이 바로

@Shared state이다.

반응형