Effekter och beroenden
Hantera sidoeffekter och injicera beroenden.
Effekter och beroenden är en gratis lektion i Swift Academy på CoddyKit. Detta är lektion 3 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Swift Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Swift Academy innehåller totalt 4 lektioner.
Varför Effects finns
Reducers måste förbli rena: givet ett state och en action får de bara mutera state. Men riktiga appar behöver sidoeffekter som nätverksanrop och timers. TCA modellerar dessa som Effects som reducern returnerar, så att mutationen förblir ren medan det asynkrona arbetet körs separat.
Det är den här uppdelningen som gör features testbara.
import ComposableArchitecture
// Reducer stays pure; side effects are values it returns.
// Returning .none means no further work.Returnera .none
När en action bara ändrar state och inte kräver något efterföljande arbete returnerar reducern .none. Det här är den vanligaste effekten och signalerar att det inte finns något asynkront arbete att utföra.
Du har redan sett detta; det är grundfallet som varje gren faller tillbaka på.
import ComposableArchitecture
Reduce { state, action in
switch action {
case .incrementTapped:
state.count += 1
return .none
}
}Effect.run för asynkront arbete
För att utföra asynkront arbete returnerar du .run. Dess closure tar emot ett send-handtag som du använder för att skicka tillbaka resultat till systemet som nya actions.
Här läser en fetch-action in data och skickar en response-action när arbetet är klart.
import ComposableArchitecture
Reduce { state, action in
switch action {
case .reloadTapped:
return .run { send in
let value = try await loadNumber()
await send(.responseReceived(value))
}
case let .responseReceived(value):
state.count = value
return .none
}
}Skicka tillbaka resultat som Actions
En effect kan inte mutera state direkt, utan skickar i stället actions via send. Reducern hanterar sedan dessa actions och uppdaterar state. Den här loopen håller alla mutationer inne i reducern.
Ett nätverkssvar blir alltså en response-action som reducern lagrar.
import ComposableArchitecture
.run { send in
let result = try await fetch()
await send(.dataLoaded(result))
}
// .dataLoaded is then handled by the reducer to set state.Hantera fel i Effects
Asynkront arbete kan kasta fel. Du kan fånga fel inne i effekten och skicka en failure-action, så att reducern kan gå över till ett feltillstånd på ett tydligt sätt.
Den valfria catch-closuren på .run tar emot det kastade felet.
import ComposableArchitecture
.run { send in
let value = try await loadNumber()
await send(.responseReceived(value))
} catch: { error, send in
await send(.loadFailed)
}Varför Dependencies är viktiga
Om en reducer anropar en nätverksklient eller läser av datumet direkt blir den svår att testa och styra. TCA löser detta med dependencies: injicerbara tjänster som reducern använder via @Dependency.
I tester ersätter du dem med förutsägbara testobjekt.
import ComposableArchitecture
// Instead of calling APIClient.shared directly,
// inject it as a dependency so tests can replace it.Property-wrappern @Dependency
Inuti en reducer deklarerar du en dependency med @Dependency och anger den via dess key path i dependency-värdena. Biblioteket tillhandahåller inbyggda dependencies som en klocka och en UUID-generator.
Här hämtar reducern den kontinuerliga klockan.
import ComposableArchitecture
@Reducer
struct TimerFeature {
@ObservableState
struct State: Equatable { var seconds = 0 }
enum Action { case start, tick }
@Dependency(\.continuousClock) var clock
var body: some ReducerOf<Self> {
Reduce { state, action in .none }
}
}Använda en Dependency i en Effect
När den är deklarerad använder du dependencyn inuti .run. Eftersom klockan injiceras kan tester tillhandahålla en testklocka som avancerar tiden på begäran.
Här tickar timern varje sekund med hjälp av den injicerade klockan.
import ComposableArchitecture
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .start:
return .run { send in
for await _ in self.clock.timer(interval: .seconds(1)) {
await send(.tick)
}
}
case .tick:
state.seconds += 1
return .none
}
}
}Definiera en egen Dependency
Du registrerar egna dependencies genom att låta ett värde följa DependencyKey och tillhandahålla ett liveValue. Sedan lägger du till en beräknad property i DependencyValues så att den får en key path.
Här blir en API-klient en förstaklassens dependency.
import ComposableArchitecture
struct NumberClient {
var fetch: () async throws -> Int
}
extension NumberClient: DependencyKey {
static let liveValue = NumberClient {
try await loadNumber()
}
}
extension DependencyValues {
var numberClient: NumberClient {
get { self[NumberClient.self] }
set { self[NumberClient.self] = newValue }
}
}Injicera den egna Dependencyn
När key path finns på plats deklarerar reducern klienten med @Dependency(\.numberClient) och anropar den i effects. I produktion används live-värdet; tester kan ersätta det.
Här hämtar en reload-action data via den injicerade klienten.
import ComposableArchitecture
@Reducer
struct NumberFeature {
@ObservableState
struct State: Equatable { var value = 0 }
enum Action { case reload, response(Int) }
@Dependency(\.numberClient) var numberClient
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .reload:
return .run { send in
let n = try await numberClient.fetch()
await send(.response(n))
}
case let .response(n):
state.value = n
return .none
}
}
}
}Avbryta effekter
Långvariga effekter, som timers, bör kunna avbrytas. Märk en effekt med ett cancellable-id och avbryt den senare från en annan åtgärd med .cancel.
Här kan timern stoppas på begäran.
import ComposableArchitecture
enum CancelID { case timer }
// Start a cancellable effect:
.run { send in /* ... */ }
.cancellable(id: CancelID.timer)
// Stop it from another action:
.cancel(id: CancelID.timer)Snabb kontroll: effekter och resultat
Kom ihåg hur en effekt kommunicerar sitt resultat tillbaka till reducern.
Sammanfattning: effekter och beroenden
Ni har lärt er hur TCA hanterar sidoeffekter och injicering:
- Reducers förblir rena och returnerar
Effect-värden;.nonebetyder att inget arbete ska utföras. .runutför asynkront arbete och skickar tillbaka resultat viaawait send(.action).- Fel hanteras med effektens
catch-closure. @Dependencyinjicerar tjänster som klockan eller era egna klienter, deklarerade viaDependencyKeyochDependencyValues.- Långvariga effekter kan göras
cancellablemed hjälp av ett id.
Härnäst ska ni sätta samman features och testa dem uttömmande.
import ComposableArchitecture
// Recap: pure reducer + Effect.run for async work
// + @Dependency for testable, injectable services.Lär dig Swift med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 122
- Lektioner
- 409
Vanliga frågor
Är lektionen ”Effekter och beroenden” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Swift Academy, inklusive ”Effekter och beroenden”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Swift Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”Effekter och beroenden”?
Hantera sidoeffekter och injicera beroenden. Ni övar på Swift Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Swift Academy?
Du behöver inga förkunskaper. Utbildningen i Swift Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.
Hur lång tid tar lektionen ”Effekter och beroenden”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Swift Academy-lektionen?
Ja. Varje Swift Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- State, Action och Reducer
- Store och SwiftUI-integration
- Effekter och beroenden
- Sätta samman och testa funktioner