TCA v1.7 Dependency

김재형·2024년 8월 13일
0
post-custom-banner

들어 가기에 앞서

TCA 편은 Reducer 패턴을 먼저 보고 와주셔야 수월합니다!

Dependency

Environment

예전 TCA 버전에서는 Environment 가 있었습니다.
작동하기 위해 필요한 의존성(Dependency)을 관리하는 환경(Environment)
라고 정의 되고 있는데요
예전에는 아래와 같은 방법으로 주입할 수 있었습니다.


struct AppState: Equatable {
    var fact: String = ""
}

enum AppAction: Equatable {
    case fetchNumberFact(Int)
    case numberFactResponse(Result<String, ApiError>)
}

struct AppEnvironment {
    var mainQueue: AnySchedulerOf<DispatchQueue>
    var numberFact: (Int) -> Effect<String, ApiError>
}

let appReducer = Reducer<AppState, AppAction, AppEnvironment> { state, action, environment in
    switch action {
    case let .fetchNumberFact(number):
        return environment.numberFact(number)
            .receive(on: environment.mainQueue)
            .catchToEffect(AppAction.numberFactResponse)
        
    case let .numberFactResponse(.success(fact)):
        state.fact = fact
        return .none
        
    case .numberFactResponse(.failure):
    	print("에러")
        return .none
    }
}

Dependency

하지만 새롭게 나온 방법을 통해 구현하게 된다면
각 의존성을 개별적으로 정의하고 관리할 수 있습니다.

| Apple Login 디펜던시 예제

struct AppleRegDependency {
    var signIn: () async throws -> ASAuthorization
}

extension AppleRegDependency: DependencyKey {
    static var liveValue: AppleRegDependency {
        return Self(
            signIn: {
                try await withCheckedThrowingContinuation { continuation in
                    
                    let request = ASAuthorizationAppleIDProvider().createRequest()
                    
                    request.requestedScopes = [.fullName, .email]
                    
                    let controller = ASAuthorizationController(authorizationRequests: [request])
                    
                    let delegate = AppleSignInDelegate(continuation: continuation)
                    
                    controller.delegate = delegate
                    controller.performRequests()
                    AppleSignInDelegateStore.shared.delegate = delegate

                }
            }
        )
    }
}
final class AppleSignInDelegateStore {
    static let shared = AppleSignInDelegateStore()
    var delegate: AppleSignInDelegate?
}

extension DependencyValues {
    var appleController: AppleRegDependency {
        get { self[AppleRegDependency.self] }
        set { self[AppleRegDependency.self] = newValue}
    }
}

@Environment?

SwiftUI에서 @Environment와 매우 비슷하지 않으신가요?

import SwiftUI

struct ContentView: View {
	/// 현재 다크모드인지 아닌지 구분합니다.
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        Text("Hello, World!")
            .foregroundColor(colorScheme == .dark ? .white : .black)
    }
}

@Environment 같은 경우는 SwiftUI를 Import 해야 사용할수 있어요
TCA에서 Dependency 시스템은 SwiftUI의 EnvironmentValues와 비슷한 역할을 하지만
SwiftUI를 Import 할 필요없이 의존성을 관리하고, 비즈니스 로직에서 의존성을 주입하고
관리하는 데 중점을 더 두었습니다.
즉 @Environment는 UI 관련 환경 값을 관리하는 데 중점을 두었다는 것이죠!

DependencyKey

DependencyValues에 특정 의존성을 추가/등록하기 위해서 DependencyKey 프로토콜을 채택합니다.

public protocol DependencyKey<Value>: TestDependencyKey {
	/// 실제 앱 동작에 사용되는 프로퍼티
	static var liveValue: Value { get }
  	associatedtype Value = Self
  	static var previewValue: Value { get }
    /// 테스트 동작에 사용되는 프로퍼티
  	static var testValue: Value { get }
    
}

extension AppleRegDependency: DependencyKey {
    static var liveValue: AppleRegDependency = Self()
}

DependencyValue

DependencyKey를 통해 value와 의존성에 접근하기 위한 키 값을 생성 합니다.
DependencyValue는 DependencyKey를 통해서 의존성을 반환하며 관리합니다.

extension DependencyValues {
    var appleController: AppleRegDependency {
        get { self[AppleRegDependency.self] }
        set { self[AppleRegDependency.self] = newValue}
    }
}

마무리 하며

무더운 여름 다들 잘 지내고 계실까요?
저는 요즘 늘어지나 싶은 맘이 들기도 한답니다.
이번 편은 TCA 의 Dependency를 알아보았는데요
이해 하셨을까라는 생각이 든답니당
모두들 고생 많으셨고 파이팅 하세요!

profile
IOS 개발자 새싹이
post-custom-banner

0개의 댓글