Kev txhim kho daim ntawv thov ntawm SwiftUI. Part 1: Dataflow thiab Redux

Kev txhim kho daim ntawv thov ntawm SwiftUI. Part 1: Dataflow thiab Redux

Tom qab mus koom lub Xeev Pawg Sib Tham ntawm WWDC 2019, kuv tau txiav txim siab mus dhia dej tob rau hauv SwiftUI. Kuv tau siv sijhawm ntau los ua haujlwm nrog nws thiab tam sim no tau pib tsim daim ntawv thov tiag tiag uas tuaj yeem pab tau rau ntau tus neeg siv.

Kuv hu ua MovieSwiftUI - qhov no yog ib qho app rau kev tshawb nrhiav cov yeeb yaj kiab tshiab thiab qub, nrog rau kev sau lawv hauv ib phau ntawv siv TMDB API. Kuv ib txwm nyiam ua yeeb yaj kiab thiab txawm tsim ib lub tuam txhab ua haujlwm hauv daim teb no, txawm tias ntev dhau los. Lub tuam txhab tsis tuaj yeem hu ua txias, tab sis daim ntawv thov yog!

Peb nco qab: rau txhua tus neeg nyeem Habr - 10 ruble luv nqi thaum tso npe rau hauv ib chav kawm Skillbox siv Habr promo code.

Skillbox pom zoo: Kev kawm online chav kawm "Profession Java developer".

Yog li MovieSwiftUI ua li cas?

  • Sib cuam tshuam nrog API - yuav luag txhua daim ntawv thov niaj hnub ua qhov no.
  • Loads asynchronous cov ntaub ntawv ntawm kev thov thiab parses JSON rau hauv Swift qauv siv Codable.
  • Qhia cov duab loaded ntawm kev thov thiab caches lawv.
  • Cov app no ​​​​rau iOS, iPadOS, thiab macOS muab qhov zoo tshaj plaws UX rau cov neeg siv ntawm cov OS.
  • Tus neeg siv tuaj yeem tsim cov ntaub ntawv thiab tsim lawv tus kheej cov npe yeeb yaj kiab. Daim ntawv thov txuag thiab kho cov neeg siv cov ntaub ntawv.
  • Kev pom, cov khoom siv thiab cov qauv tau muab cais kom meej siv tus qauv Redux. Cov ntaub ntawv ntws ntawm no yog unidirectional. Nws tuaj yeem muab tag nrho cached, rov qab thiab sau dua.
  • Daim ntawv thov siv cov khoom tseem ceeb ntawm SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal, thiab lwm yam. Nws kuj muab kev cai saib, gestures, UI/UX.

Kev txhim kho daim ntawv thov ntawm SwiftUI. Part 1: Dataflow thiab Redux
Qhov tseeb, cov animation yog du, GIF tau tig tawm me ntsis jerky

Ua haujlwm ntawm lub app tau muab ntau yam kev paub rau kuv thiab tag nrho nws yog qhov kev paub zoo. Kuv tuaj yeem sau daim ntawv thov ua haujlwm tau zoo, thaum lub Cuaj Hli kuv yuav txhim kho nws thiab tshaj tawm hauv AppStore, ib txhij nrog kev tso tawm ntawm iOS 13.

Redux, BindableObject thiab EnvironmentObject

Kev txhim kho daim ntawv thov ntawm SwiftUI. Part 1: Dataflow thiab Redux

Kuv tau ua haujlwm nrog Redux tau li ob xyoos tam sim no, yog li kuv kuj paub zoo txog nws. Hauv particular, kuv siv nws nyob rau hauv lub frontend rau React lub vev xaib, nrog rau kev tsim cov haiv neeg iOS (Swift) thiab Android (Kotlin) daim ntawv thov.

Kuv yeej tsis khuv xim xaiv Redux li cov ntaub ntawv ntws architecture rau kev tsim SwiftUI daim ntawv thov. Qhov nyuaj tshaj plaws thaum siv Redux hauv UIKit app ua haujlwm nrog lub khw thiab tau txais thiab khaws cov ntaub ntawv thiab kos duab rau koj cov kev xav / cov khoom. Ua li no, kuv yuav tsum tau tsim ib hom tsev qiv ntawv ntawm cov khoom sib txuas (siv ReSwift thiab ReKotlin). Ua haujlwm zoo, tab sis ntau code. Hmoov tsis zoo, nws tsis yog (tsis tau) qhib qhov chaw.

Xov xwm zoo! Tib yam uas yuav tsum txhawj xeeb nrog SwiftUI - yog tias koj npaj yuav siv Redux - yog cov khw muag khoom, xeev, thiab cov khoom txo qis. Kev cuam tshuam nrog lub khw yog saib xyuas los ntawm SwiftUI ua tsaug rau @EnvironmentObject. Yog li, khw pib nrog BindableObject.

Kuv tsim ib pob Swift yooj yim, SwiftUIFlux, uas muab kev siv yooj yim ntawm Redux. Hauv kuv rooj plaub nws yog ib feem ntawm MovieSwiftUI. kuv thiab tau sau ib kauj ruam los ntawm kauj ruam qhia, uas yuav pab tau koj siv cov khoom no.

Ua li cas nws ua hauj lwm?

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

Txhua zaus koj ua qhov kev txiav txim, koj qhib lub gearbox. Nws yuav ntsuas cov kev ua raws li lub xeev tam sim no ntawm daim ntawv thov. Tom qab ntawd nws yuav rov qab lub xeev hloov tshiab raws li hom kev ua thiab cov ntaub ntawv.

Zoo, txij li lub khw yog BindableObject, nws yuav ceeb toom rau SwiftUI thaum nws cov nqi hloov pauv uas siv cov cuab yeej willChange muab los ntawm PassthroughSubject. Qhov no yog vim BindableObject yuav tsum muab PublisherType, tab sis kev siv raws tu qauv yog lub luag haujlwm rau kev tswj hwm nws. Zuag qhia tag nrho, qhov no yog lub cuab yeej muaj zog heev los ntawm Apple. Raws li, nyob rau hauv lub voj voog rendering tom ntej, SwiftUI yuav pab ua kom lub cev ntawm cov kev xav raws li lub xeev hloov.

Qhov tseeb, qhov no yog tag nrho lub siab thiab khawv koob ntawm SwiftUI. Tam sim no, nyob rau hauv txhua qhov kev pom uas sau npe rau hauv ib lub xeev, qhov kev pom yuav raug ua raws li cov ntaub ntawv tau txais los ntawm lub xeev thiab qhov twg tau hloov pauv.

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

Lub khw tau txhaj tshuaj raws li EnvironmentObject thaum daim ntawv thov pib thiab nkag mus rau txhua qhov kev pom siv @EnvironmentObject. Tsis muaj kev nplua rau kev ua haujlwm vim tias cov khoom tau muab tau sai sai los yog xam los ntawm lub xeev daim ntawv thov.

Cov cai saum toj no hloov cov duab yog tias daim ntawv tshaj tawm yeeb yaj kiab hloov pauv.

Thiab qhov no yog ua tiav nrog tsuas yog ib txoj kab, nrog kev pab los ntawm cov views uas txuas nrog lub xeev. Yog tias koj tau ua haujlwm nrog ReSwift ntawm iOS lossis txawm tias txuas Nrog React, koj yuav nkag siab cov khawv koob ntawm SwiftUI.

Tam sim no koj tuaj yeem sim qhib qhov kev txiav txim thiab tshaj tawm lub xeev tshiab. Nov yog ib qho piv txwv nyuaj dua.

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!]))
            }
        }
    }
}

Hauv cov cai saum toj no, kuv tab tom siv .onDelete kev txiav txim los ntawm SwiftUI rau txhua tus IP. Qhov no tso cai rau kab hauv daim ntawv los tso saib qhov qub iOS los so kom tshem tawm. Yog li thaum tus neeg siv kov lub pob rho tawm, nws ua rau cov kev coj ua thiab tshem tawm cov yeeb yaj kiab los ntawm cov npe.

Zoo, txij li daim ntawv teev cov cuab yeej tau muab los ntawm BindableObject xeev thiab tau txhaj tshuaj raws li EnvironmentObject, SwiftUI hloov kho cov npe vim ForEach cuam tshuam nrog cov yeeb yaj kiab suav cov cuab yeej.

Nov yog ib feem ntawm MoviesState reducer:

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
}

Lub reducer raug tua thaum koj xa ib qho kev txiav txim thiab xa rov qab rau lub xeev tshiab, raws li tau hais los saum toj no.

Kuv yuav tsis mus rau hauv kev nthuav dav - yuav ua li cas SwiftUI yeej paub tias yuav ua li cas. Yuav kom nkag siab qhov no tob dua, nws tsim nyog saib WWDC kev sib ntsib ntawm cov ntaub ntawv ntws hauv SwiftUI. Nws kuj piav qhia meej vim li cas thiab thaum twg siv State, @Binding, ObjectBinding thiab EnvironmentObject.

Skillbox pom zoo:

Tau qhov twg los: www.hab.com

Ntxiv ib saib