Swift Academy · Oppitunti

Efektit ja riippuvuudet

Käsittele sivuvaikutuksia ja injektoi riippuvuuksia.

Oppitunti 3/413 vaihetta

Efektit ja riippuvuudet on ilmainen Swift Academy-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Swift Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Swift Academy-kurssilla on yhteensä 4 oppituntia.

Miksi efektejä tarvitaan

Reducerien on pysyttävä puhtaina: kun niille annetaan tila ja toiminto, ne muuttavat vain tilaa. Todelliset sovellukset tarvitsevat kuitenkin sivuvaikutuksia, kuten verkkopyyntöjä ja ajastimia. TCA mallintaa nämä reducerin palauttamina Effects-efekteinä, jolloin tilan muuttaminen pysyy puhtaana ja asynkroninen työ suoritetaan erikseen.

Tämä erottelu tekee ominaisuuksista testattavia.

import ComposableArchitecture

// Reducer stays pure; side effects are values it returns.
// Returning .none means no further work.

.none-arvon palauttaminen

Kun toiminto muuttaa vain tilaa eikä tarvitse mitään jatkotoimia, reducer palauttaa arvon .none. Tämä on yleisin efekti ja ilmaisee, ettei suoritettavaa asynkronista työtä ole.

Olette nähneet tämän jo; se on oletusarvo, johon jokainen haara lopulta palaa.

import ComposableArchitecture

Reduce { state, action in
    switch action {
    case .incrementTapped:
        state.count += 1
        return .none
    }
}

Effect.run asynkroniseen työhön

Asynkroninen työ suoritetaan palauttamalla .run. Sen sulkeuma vastaanottaa send-kahvan, jonka avulla tulokset välitetään järjestelmään uusina toimintoina.

Tässä fetch-toiminto lataa tiedot ja lähettää vastaustoiminnon, kun työ on valmis.

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
    }
}

Tulosten välittäminen takaisin toimintoina

Efekti ei voi muuttaa tilaa suoraan, vaan se lähettää toimintoja send-kahvan kautta. Reducer käsittelee nämä toiminnot ja päivittää tilaa. Tämä silmukka pitää kaikki muutokset reducerin sisällä.

Verkkovastauksesta tulee siis vastaustoiminto, jonka reducer tallentaa.

import ComposableArchitecture

.run { send in
    let result = try await fetch()
    await send(.dataLoaded(result))
}
// .dataLoaded is then handled by the reducer to set state.

Virheiden käsittely efekteissä

Asynkroninen työ voi heittää virheen. Voitte siepata virheet efektin sisällä ja lähettää epäonnistumisesta kertovan toiminnon, jolloin reducer siirtää tilan hallitusti virhetilaan.

.run-efektin valinnainen catch-sulkeuma vastaanottaa heitetyn virheen.

import ComposableArchitecture

.run { send in
    let value = try await loadNumber()
    await send(.responseReceived(value))
} catch: { error, send in
    await send(.loadFailed)
}

Miksi riippuvuudet ovat tärkeitä

Jos reducer kutsuu verkkokirjastoa tai lukee päivämäärän suoraan, sitä on vaikea testata ja hallita. TCA ratkaisee tämän dependencies-riippuvuuksilla: injektoitavilla palveluilla, joita reducer käyttää @Dependency-merkinnän kautta.

Testeissä vaihdatte ne ennakoitavasti toimiviin feikkeihin.

import ComposableArchitecture

// Instead of calling APIClient.shared directly,
// inject it as a dependency so tests can replace it.

@Dependency-ominaisuuswrapperi

Reducerin sisällä riippuvuus määritellään @Dependency-merkinnällä, jolle annetaan nimi riippuvuusarvojen key path -polkuna. Kirjasto tarjoaa valmiita riippuvuuksia, kuten kellon ja UUID-generaattorin.

Tässä reducer ottaa käyttöön jatkuvan kellon.

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 }
    }
}

Riippuvuuden käyttäminen efektissä

Kun riippuvuus on määritelty, sitä käytetään .run-efektin sisällä. Koska kello injektoidaan, testit voivat käyttää testikelloa, joka siirtää aikaa tarvittaessa eteenpäin.

Tässä ajastin tikittää sekunnin välein injektoidun kellon avulla.

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
        }
    }
}

Oman riippuvuuden määrittäminen

Mukautetut riippuvuudet rekisteröidään toteuttamalla DependencyKey ja tarjoamalla liveValue. Tämän jälkeen DependencyValues-tyyppiin lisätään laskettu ominaisuus, jotta riippuvuudelle saadaan key path -polku.

Tässä API-asiakasohjelmasta tulee ensimmäisen luokan riippuvuus.

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 }
    }
}

Mukautetun riippuvuuden injektointi

Kun key path -polku on määritetty, reducer ilmoittaa asiakkaan @Dependency(\.numberClient)-merkinnällä ja kutsuu sitä efektien sisällä. Tuotannossa käytetään live-arvoa, kun taas testit korvaavat sen omalla toteutuksellaan.

Tässä reload-toiminto hakee tiedot injektoidun asiakkaan kautta.

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
            }
        }
    }
}

Tehosteiden peruuttaminen

Pitkäkestoisten tehosteiden, kuten ajastimien, pitäisi olla peruttavissa. Merkitse tehoste cancellable-tunnisteella ja peruuta se myöhemmin toisesta toiminnosta .cancel-kutsulla.

Tässä ajastimen voi pysäyttää tarvittaessa.

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)

Pikatarkistus: tehosteet ja tulokset

Palauttakaa mieleenne, miten tehoste välittää tuloksensa reducerille.

Kertaus: tehosteet ja riippuvuudet

Opitte, miten TCA käsittelee sivuvaikutuksia ja riippuvuuksien injektointia:

  • Reducerit pysyvät puhtaina ja palauttavat Effect-arvoja; .none tarkoittaa, ettei suoritettavaa työtä ole.
  • .run suorittaa asynkronista työtä ja välittää tulokset takaisin komennolla await send(.action).
  • Virheet käsitellään tehosteen catch-sulkeumassa.
  • @Dependency injektoi palveluita, kuten kellon tai omat clientinne, jotka ilmoitetaan DependencyKey- ja DependencyValues-tyypeillä.
  • Pitkäkestoisista tehosteista voi tehdä cancellable-tunnisteen avulla peruttavia.

Seuraavaksi koostatte toiminnallisuuksia yhteen ja testaatte ne kattavasti.

import ComposableArchitecture

// Recap: pure reducer + Effect.run for async work
// + @Dependency for testable, injectable services.
Aloita maksutta

Opi Swift tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
122
Oppitunnit
409

Usein kysytyt kysymykset

Onko oppitunti ”Efektit ja riippuvuudet” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Swift Academy-oppimispolun 3 oppituntia, myös oppitunnin “Efektit ja riippuvuudet”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Swift Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Efektit ja riippuvuudet”?

Käsittele sivuvaikutuksia ja injektoi riippuvuuksia. Harjoittelet Swift Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Swift Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Swift Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.

Kuinka kauan ”Efektit ja riippuvuudet”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Swift Academy-oppitunnilla?

Kyllä. Jokainen Swift Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Tila, toiminto ja reducer
  2. Store ja SwiftUI-integraatio
  3. Efektit ja riippuvuudet
  4. Ominaisuuksien koostaminen ja testaaminen
← Takaisin: Swift Academy