TCA Nedir?#
The Composable Architecture (TCA), Brandon Williams ve Stephen Celis tarafından geliştirilen, SwiftUI için tasarlanmış bir uygulama mimarisidir. Unidirectional data flow prensibine dayanır ve test edilebilirliği birinci sınıf vatandaş olarak ele alır.
Temel Kavramlar#
TCA’nın beş temel bileşeni vardır:
| Bileşen | Görev |
|---|
| State | Ekranın tüm verisi |
| Action | Gerçekleşen olaylar |
| Reducer | State + Action → yeni State |
| Store | Runtime: state tutar, action gönderir |
| Effect | Yan etkiler (network, timer vb.) |
Basit Bir Örnek: Sayaç#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| import ComposableArchitecture
import SwiftUI
// 1. State
struct CounterFeature: Reducer {
struct State: Equatable {
var count = 0
var isLoading = false
}
// 2. Action
enum Action {
case incrementTapped
case decrementTapped
case factButtonTapped
case factResponse(String)
}
// 3. Reducer
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .incrementTapped:
state.count += 1
return .none
case .decrementTapped:
state.count -= 1
return .none
case .factButtonTapped:
state.isLoading = true
return .run { [count = state.count] send in
let fact = try await fetchFact(for: count)
await send(.factResponse(fact))
}
case let .factResponse(fact):
state.isLoading = false
// fact'ı state'e kaydet
return .none
}
}
}
}
|
View Katmanı#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| struct CounterView: View {
let store: StoreOf<CounterFeature>
var body: some View {
WithViewStore(store, observe: { $0 }) { viewStore in
VStack(spacing: 20) {
Text("\(viewStore.count)")
.font(.largeTitle.bold())
HStack {
Button("-") {
viewStore.send(.decrementTapped)
}
.buttonStyle(.bordered)
Button("+") {
viewStore.send(.incrementTapped)
}
.buttonStyle(.borderedProminent)
}
if viewStore.isLoading {
ProgressView()
} else {
Button("Fakt Al") {
viewStore.send(.factButtonTapped)
}
}
}
}
}
}
|
Test Yazımı#
TCA’nın en güçlü yanı test edilebilirlik:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| @MainActor
final class CounterFeatureTests: XCTestCase {
func testIncrement() async {
let store = TestStore(initialState: CounterFeature.State()) {
CounterFeature()
}
await store.send(.incrementTapped) {
$0.count = 1
}
await store.send(.incrementTapped) {
$0.count = 2
}
await store.send(.decrementTapped) {
$0.count = 1
}
}
}
|
Composability: Feature’ları Birleştirme#
TCA’nın adındaki “Composable” özelliği, küçük feature’ları büyük uygulamalarda birleştirmeye yarar:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| struct AppFeature: Reducer {
struct State {
var tab1 = CounterFeature.State()
var tab2 = ProfileFeature.State()
}
enum Action {
case tab1(CounterFeature.Action)
case tab2(ProfileFeature.Action)
}
var body: some ReducerOf<Self> {
Scope(state: \.tab1, action: /Action.tab1) {
CounterFeature()
}
Scope(state: \.tab2, action: /Action.tab2) {
ProfileFeature()
}
}
}
|
Sonuç#
TCA, büyük ölçekli SwiftUI uygulamaları için güçlü bir mimari sunuyor. Test edilebilirlik, öngörülebilirlik ve bileşen yeniden kullanımı açısından rakipsiz. Öğrenme eğrisi dik olsa da, orta ve büyük projelerde kesinlikle değer.