TCA 편은 Reducer 패턴을 먼저 보고 와주셔야 수월합니다!
예전 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
}
}
하지만 새롭게 나온 방법을 통해 구현하게 된다면
각 의존성을 개별적으로 정의하고 관리할 수 있습니다.
| 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}
}
}
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 관련 환경 값을 관리하는 데 중점을 두었다는 것이죠!
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()
}
DependencyKey를 통해 value와 의존성에 접근하기 위한 키 값을 생성 합니다.
DependencyValue는 DependencyKey를 통해서 의존성을 반환하며 관리합니다.
extension DependencyValues {
var appleController: AppleRegDependency {
get { self[AppleRegDependency.self] }
set { self[AppleRegDependency.self] = newValue}
}
}
무더운 여름 다들 잘 지내고 계실까요?
저는 요즘 늘어지나 싶은 맘이 들기도 한답니다.
이번 편은 TCA 의 Dependency를 알아보았는데요
이해 하셨을까라는 생각이 든답니당
모두들 고생 많으셨고 파이팅 하세요!