Forbairt feidhmchlár ar SwiftUI. Cuid 1: Dataflow agus Redux

Forbairt feidhmchlár ar SwiftUI. Cuid 1: Dataflow agus Redux

Tar éis dom freastal ar sheisiún Staid an Aontais ag WWDC 2019, chinn mé tumadh domhain a dhéanamh ar SwiftUI. Tá go leor ama caite agam ag obair leis agus anois tá mé tosaithe ag forbairt feidhmchlár fíor a d'fhéadfadh a bheith úsáideach do raon leathan úsáideoirí.

MovieSwiftUI a thug mé air - is aip é seo chun scannáin nua agus sean a chuardach, chomh maith lena mbailiú i mbailiúchán ag baint úsáide as API TMDB. Is breá liom i gcónaí scannáin agus fiú chruthaigh cuideachta ag obair sa réimse seo, cé go i bhfad ó shin. Is ar éigean a d’fhéadfaí glaoch ar an gcuideachta fionnuar, ach bhí an t-iarratas!

Meabhraímid: do léitheoirí uile "Habr" - lascaine de 10 rúbal nuair a chláraíonn siad in aon chúrsa Scilbox ag baint úsáide as an gcód bolscaireachta "Habr".

Molann Skillbox: Cúrsa oideachais ar líne "Forbróir Java Gairm".

Mar sin cad is féidir le MovieSwiftUI a dhéanamh?

  • Idirghníomhaíonn sé leis an API - déanann beagnach aon fheidhmchlár nua-aimseartha é seo.
  • Lódálann sé sonraí asincrónacha ar iarratais agus parsálann sé JSON isteach sa mhúnla Swift ag baint úsáide as Inchódaithe.
  • Taispeánann sé íomhánna lódáilte ar iarratas agus cuireann sé i dtaisce iad.
  • Soláthraíonn an aip seo le haghaidh iOS, iPadOS, agus macOS an UX is fearr d'úsáideoirí na OSes seo.
  • Is féidir leis an úsáideoir sonraí a ghiniúint agus a liostaí scannán féin a chruthú. Sábhálann agus athshlánóidh an feidhmchlár sonraí úsáideora.
  • Tá radhairc, comhpháirteanna agus samhlacha deighilte go soiléir ag baint úsáide as patrún Redux. Tá an sreabhadh sonraí anseo aontreoch. Is féidir é a thaisceadh go hiomlán, a athchóiriú agus a fhorscríobh.
  • Úsáideann an feidhmchlár na comhpháirteanna bunúsacha de SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal, etc. Soláthraíonn sé freisin tuairimí saincheaptha, gothaí, Chomhéadain / UX.

Forbairt feidhmchlár ar SwiftUI. Cuid 1: Dataflow agus Redux
Go deimhin, tá an beochan réidh, d'éirigh an GIF amach beagán jerky

Thug obair ar an aip go leor taithí dom agus ar an iomlán ba eispéireas dearfach é. Bhí mé in ann feidhmchlár lánfheidhmiúil a scríobh, i mí Mheán Fómhair feabhsóidh mé é agus foilseoidh mé é san AppStore, ag an am céanna le scaoileadh iOS 13.

Redux, BindableObject agus EnvironmentObject

Forbairt feidhmchlár ar SwiftUI. Cuid 1: Dataflow agus Redux

Tá mé ag obair le Redux le thart ar dhá bhliain anois, agus mar sin tá mé sách eolach air. Go háirithe, úsáidim é san tosaigh le haghaidh Freagairt láithreán gréasáin, chomh maith le feidhmchláir dhúchasacha iOS (Swift) agus Android (Kotlin) a fhorbairt.

Ní raibh aiféala orm riamh Redux a roghnú mar an ailtireacht sreafa sonraí chun feidhmchlár SwiftUI a thógáil. Is iad na codanna is dúshlánaí agus Redux in úsáid in aip UIKit ná oibriú leis an stór agus sonraí a fháil agus a aisghabháil agus iad a mhapáil chuig do thuairimí/comhpháirteanna. Chun seo a dhéanamh, bhí orm leabharlann de chineál nascóirí a chruthú (ag baint úsáide as ReSwift agus ReKotlin). Oibríonn sé go maith, ach go leor cód. Ar an drochuair, níl sé (fós) foinse oscailte.

Nuacht Maith! Is iad na hábhair imní ach amháin le SwiftUI - má tá sé ar intinn agat Redux a úsáid - ná siopaí, stáit agus laghdaitheoirí. Tugann SwiftUI aire iomlán do idirghníomhaíocht leis an siopa a bhuíochas do @EnvironmentObject. Mar sin, tosaíonn an siopa le BindableObject.

Chruthaigh mé pacáiste Swift simplí, SwiftUIFlux, a sholáthraíonn úsáid bhunúsach Redux. I mo chás féin is cuid de MovieSwiftUI é. Mise freisin scríobh sé céim-ar-chéim teagaisc, a chabhróidh leat an comhpháirt seo a úsáid.

Conas a oibríonn sé?

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

Gach uair a spreagann tú gníomh, gníomhaíonn tú an giarbhosca. Déanfaidh sé meastóireacht ar ghníomhaíochtaí de réir staid reatha an iarratais. Tabharfaidh sé ar ais ansin stát modhnaithe nua i gcomhréir leis an gcineál gníomhaíochta agus sonraí.

Bhuel, ós rud é gur BindableObject é an siopa, cuirfidh sé in iúl do SwiftUI nuair a athraíonn a luach ag baint úsáide as an maoin willChange a sholáthraíonn PassthroughSubject. Tá sé seo amhlaidh toisc go gcaithfidh an BindableObject PublisherType a sholáthar, ach tá cur i bhfeidhm an phrótacail freagrach as é a bhainistiú. Ar an iomlán, is uirlis an-chumhachtach é seo ó Apple. Dá réir sin, sa chéad timthriall rindreála eile, cabhróidh SwiftUI le corp na dtuairimí a thabhairt de réir an athraithe stáit.

I ndáiríre, is é seo croí agus draíocht SwiftUI ar fad. Anois, in aon tuairim a shíníonn do stát, déanfar an dearcadh a thabhairt de réir na sonraí a fhaightear ón stát agus an méid a d'athraigh.

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

Instealladh é an Store mar EnvironmentObject nuair a thosaíonn an feidhmchlár agus ansin bíonn rochtain air in aon radharc ag úsáid @EnvironmentObject. Níl aon phionós feidhmíochta ann toisc go ndéantar maoine díorthaithe a aisghabháil nó a ríomh go tapa ó staid an iarratais.

Athraíonn an cód thuas an íomhá má athraíonn an póstaer scannáin.

Agus déantar é seo i ndáiríre le líne amháin, le cabhair a bhfuil tuairimí ceangailte leis an stát. Má d'oibrigh tú le ReSwift ar iOS nó fiú ceangal le React, tuigfidh tú draíocht SwiftUI.

Anois is féidir leat iarracht a dhéanamh an gníomh a ghníomhachtú agus an stát nua a fhoilsiú. Seo sampla níos casta.

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

Sa chód thuas tá mé ag baint úsáide as an ngníomh .onDelete ó SwiftUI do gach IP. Ligeann sé seo don tsraith nua ar an liosta an gnáth-svipe iOS a thaispeáint le scriosadh. Mar sin nuair a dhéanann an t-úsáideoir teagmháil leis an gcnaipe scriosta, spreagann sé an gníomh comhfhreagrach agus bainfidh sé an scannán ón liosta.

Bhuel, ós rud é go bhfuil maoin an liosta díorthaithe ó staid BindableObject agus go ndéantar é a instealladh mar EnvironmentObject, déanann SwiftUI an liosta a nuashonrú toisc go bhfuil ForEach bainteach leis an maoin ríofa scannáin.

Seo cuid den laghdaitheoir MoviesState:

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
}

Déantar an laghdaitheoir a fhorghníomhú nuair a sheolann tú caingean agus nuair a sheolann tú stát nua ar ais, mar a dúradh thuas.

Ní dhéanfaidh mé sonraí go fóill - conas atá a fhios ag SwiftUI cad atá le taispeáint. Chun é seo a thuiscint níos doimhne, is fiú féach ar sheisiún WWDC ar shreabhadh sonraí i SwiftUI. Míníonn sé go mion freisin cén fáth agus cén uair ba cheart é a úsáid Stáit, @Binding, ObjectBinding agus EnvironmentObject.

Molann Skillbox:

Foinse: will.com

Add a comment