Aplikazioen garapena SwiftUI-n. 1. zatia: Dataflow eta Redux

Aplikazioen garapena SwiftUI-n. 1. zatia: Dataflow eta Redux

WWDC 2019ko Batasunaren Estatuko saioan parte hartu ondoren, SwiftUI-n sakontzea erabaki nuen. Denbora asko eman dut horrekin lanean eta erabiltzaile askorentzat erabilgarria izan daitekeen benetako aplikazio bat garatzen hasi naiz orain.

MovieSwiftUI deitu nion - film berriak eta zaharrak bilatzeko aplikazioa da, baita bilduma batean biltzeko ere. TMDB APIa. Betidanik gustatu izan zait filma, eta baita alor horretan lan egiten duen enpresa bat sortu ere, aspaldikoa bada ere. Konpainia nekez deitu zitekeen cool, baina aplikazioa bai!

Gogoratzen dugu: "Habr" irakurle guztientzat - 10 errubloko deskontua "Habr" promozio-kodea erabiliz Skillbox-eko edozein ikastarotan izena ematean.

Skillbox-ek gomendatzen du: Hezkuntza online ikastaroa "Lanbideko Java garatzailea".

Beraz, zer egin dezake MovieSwiftUI-k?

  • APIarekin elkarreragiten du - ia edozein aplikazio modernok egiten du hori.
  • Eskaeretan datu asinkronoak kargatzen ditu eta JSON Swift ereduan analizatzen du erabiliz Kodegarria.
  • Eskaeran kargatutako irudiak erakusten ditu eta cachean gordetzen ditu.
  • iOS, iPadOS eta macOSentzako aplikazio honek UX onena eskaintzen die OS hauen erabiltzaileei.
  • Erabiltzaileak datuak sor ditzake eta bere pelikula zerrendak sor ditzake. Aplikazioak erabiltzaileen datuak gordetzen eta leheneratzen ditu.
  • Ikuspegiak, osagaiak eta ereduak argi eta garbi bereizten dira Redux eredua erabiliz. Hemen datu-fluxua norabide bakarrekoa da. Erabat cachean gorde daiteke, leheneratu eta gainidatzi.
  • Aplikazioak SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal, etab. oinarrizko osagaiak erabiltzen ditu. Ikuspegi pertsonalizatuak, keinuak, UI/UX ere eskaintzen ditu.

Aplikazioen garapena SwiftUI-n. 1. zatia: Dataflow eta Redux
Izan ere, animazioa leuna da, GIFa apur bat apur bat bihurritu zen

Aplikazioan lan egiteak esperientzia handia eman zidan eta orokorrean esperientzia positiboa izan zen. Aplikazio guztiz funtzionala idatzi ahal izan nuen, irailean hobetuko dut eta AppStore-n argitaratuko dut, iOS 13 kaleratzearekin batera.

Redux, BindableObject eta EnvironmentObject

Aplikazioen garapena SwiftUI-n. 1. zatia: Dataflow eta Redux

Orain bi urte inguru daramatzat Redux-ekin lanean, eta, beraz, nahiko ondo ezagutzen dut. Bereziki, frontend-ean erabiltzen dut Erreakzionatzeko webgunea, baita jatorrizko iOS (Swift) eta Android (Kotlin) aplikazioak garatzeko ere.

Inoiz ez naiz damutu Redux aukeratzeaz SwiftUI aplikazio bat eraikitzeko datu-fluxuaren arkitektura gisa. UIKit aplikazio batean Redux erabiltzean zatirik zailena dendarekin lan egitea eta datuak lortzea eta berreskuratzea eta zure ikuspegi/osagaiekin mapatzea dira. Horretarako, konektoreen liburutegi moduko bat sortu behar izan nuen (ReSwift eta ReKotlin erabiliz). Ondo funtzionatzen du, baina kode asko. Zoritxarrez, ez da (oraindik) kode irekia.

Berri onak! SwiftUIrekin kezkatu beharreko gauza bakarrak - Redux erabiltzeko asmoa baduzu - dendak, estatuak eta murriztaileak dira. SwiftUI-k guztiz zaintzen du dendarekin elkarrekintza @EnvironmentObject-i esker. Beraz, denda BindableObject batekin hasten da.

Swift pakete sinple bat sortu nuen, SwiftUIFlux, Redux-en oinarrizko erabilera eskaintzen duena. Nire kasuan MovieSwiftUIren parte da. Nik ere urratsez urrats tutorial bat idatzi zuen, osagai hau erabiltzen lagunduko dizu.

Nola funtzionatzen du?

final public class Store<State: FluxState>: BindableObject {
    public let willChange = PassthroughSubject<Void, Never>()
        
    private(set) public var state: State
    
    private func _dispatch(action: Action) {
        willChange.send()
        state = reducer(state, action)
    }
}

Ekintza bat abiarazten duzun bakoitzean, aldaketa-kutxa aktibatzen duzu. Ekintzak ebaluatuko ditu aplikazioaren egungo egoeraren arabera. Ondoren, aldatutako egoera berri bat itzuliko du ekintza motaren eta datuen arabera.

Beno, denda BindableObject bat denez, SwiftUIri jakinaraziko dio bere balioa aldatzen denean PassthroughSubject-ek emandako willChange propietatea erabiliz. Hau da, BindableObject-ek PublisherType bat eman behar duelako, baina protokoloaren ezarpenak kudeatzeaz arduratzen da. Orokorrean, Appleren tresna oso indartsua da. Horren arabera, hurrengo errendatze-zikloan, SwiftUI-k bistaren gorputza egoera-aldaketaren arabera errendatzen lagunduko du.

Egia esan, hau da SwiftUIren bihotza eta magia guztia. Orain, egoera batera harpidetzen den edozein ikuspegitan, estatutik zer datu jasotzen diren eta zer aldatu den arabera emango da ikuspegia.

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
 
    var window: UIWindow?
 
 
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            
            let controller = UIHostingController(rootView: HomeView().environmentObject(store))
            window.rootViewController = controller
            self.window = window
            window.makeKeyAndVisible()
        }
    }
}
 
struct CustomListCoverRow : View {
    @EnvironmentObject var store: Store<AppState>
    
    let movieId: Int
    var movie: Movie! {
        return store.state.moviesState.movies[movieId]
    }
    
    var body: some View {
        HStack(alignment: .center, spacing: 0) {
            Image(movie.poster)
        }.listRowInsets(EdgeInsets())
    }
}

Denda EnvironmentObject gisa injektatzen da aplikazioa abiarazten denean eta, gero, edozein ikuspegitan eskuragarri dago @EnvironmentObject erabiliz. Ez dago errendimendu-zigorra, eratorritako propietateak azkar berreskuratzen edo kalkulatzen direlako aplikazioaren egoeratik.

Goiko kodeak irudia aldatzen du filmaren kartela aldatzen bada.

Eta hori benetan lerro bakarrarekin egiten da, zeinen laguntzarekin ikuspegiak estatuarekin lotzen diren. ReSwift-ekin lan egin baduzu iOS edo are gehiago konektatzeko React-ekin, SwiftUIren magia ulertuko duzu.

Orain ekintza aktibatzen eta egoera berria argitaratzen saia zaitezke. Hona hemen adibide konplexuago bat.

struct CustomListDetail : View {
    @EnvironmentObject var store: Store<AppState>
 
    let listId: Int
    
    var list: CustomList {
        store.state.moviesState.customLists[listId]!
    }
    
    var movies: [Int] {
        list.movies.sortedMoviesIds(by: .byReleaseDate, state: store.state)
    }
    
    var body: some View {
        List {
            ForEach(movies) { movie in
                NavigationLink(destination: MovieDetail(movieId: movie).environmentObject(self.store)) {
                    MovieRow(movieId: movie, displayListImage: false)
                }
            }.onDelete { (index) in
               self.store.dispatch(action: MoviesActions.RemoveMovieFromCustomList(list: self.listId, movie: self.movies[index.first!]))
            }
        }
    }
}

Goiko kodean SwiftUI-ko .onDelete ekintza erabiltzen ari naiz IP bakoitzeko. Horri esker, zerrendako errenkadak ezabatzeko iOS irristatze normala bistaratzeko aukera ematen du. Beraz, erabiltzaileak ezabatzeko botoia ukitzen duenean, dagokion ekintza abiarazten du eta filma zerrendatik kentzen du.

Beno, zerrendaren propietatea BindableObject egoeratik eratorria denez eta EnvironmentObject gisa injektatzen denez, SwiftUI-k zerrenda eguneratzen du ForEach filmak kalkulatutako propietatearekin lotuta dagoelako.

Hona hemen MoviesState erreduzitzailearen zati bat:

func moviesStateReducer(state: MoviesState, action: Action) -> MoviesState {
    var state = state
    switch action {
    
    // other actions.
    
    case let action as MoviesActions.AddMovieToCustomList:
        state.customLists[action.list]?.movies.append(action.movie)
        
    case let action as MoviesActions.RemoveMovieFromCustomList:
        state.customLists[action.list]?.movies.removeAll{ $0 == action.movie }
        
    default:
        break
    }
    return state
}

Erreduzitzailea ekintza bat bidaltzen duzunean eta egoera berri bat itzultzen duzunean exekutatuko da, goian esan bezala.

Oraindik ez naiz xehetasunetan sartuko - nola dakien benetan zer erakutsi SwiftUI-k. Hau sakonago ulertzeko, merezi du ikusi datu-fluxuari buruzko WWDC saioa SwiftUI-n. Era berean, zehatz-mehatz azaltzen du zergatik eta noiz erabili Estatuko, @Binding, ObjectBinding eta EnvironmentObject.

Skillbox-ek gomendatzen du:

Iturria: www.habr.com

Gehitu iruzkin berria