Leasachadh tagraidh air SwiftUI. Pàirt 1: Dataflow agus Redux
Às deidh dhomh a bhith an làthair aig seisean Stàite an Aonaidh aig WWDC 2019, chuir mi romham dàibheadh domhainn a-steach do SwiftUI. Tha mi air tòrr ùine a chuir seachad ag obair còmhla ris agus tha mi a-nis air tòiseachadh a’ leasachadh fìor thagradh a dh’ fhaodadh a bhith feumail do raon farsaing de luchd-cleachdaidh.
Thug mi MovieSwiftUI air - is e app a tha seo airson filmichean ùr is sean a lorg, a bharrachd air an cruinneachadh ann an cruinneachadh a’ cleachdadh API TMDB. Bha mi a-riamh dèidheil air filmichean agus eadhon air companaidh a chruthachadh ag obair san raon seo, ged a bha mi o chionn fhada. Cha mhòr gum b’ urrainn don chompanaidh a bhith fionnar, ach bha an tagradh!
Tha sinn a ’cur nar cuimhne:airson a h-uile leughadair de "Habr" - lasachadh de 10 rubles nuair a chlàraicheas tu ann an cùrsa sam bith Skillbox a 'cleachdadh a' chòd adhartachaidh "Habr".
Mar sin dè as urrainn dha MovieSwiftUI a dhèanamh?
Ag eadar-obrachadh leis an API - bidh cha mhòr tagradh ùr-nodha a’ dèanamh seo.
A’ luchdachadh dàta asyncronach air iarrtasan agus a’ parsadh JSON a-steach don mhodal Swift a’ cleachdadh Codail.
A’ sealltainn ìomhaighean air an luchdachadh ma thèid an iarraidh agus gan tasgadh.
Tha an aplacaid seo airson iOS, iPadOS, agus macOS a’ toirt seachad an UX as fheàrr airson luchd-cleachdaidh nan OSan sin.
Faodaidh an neach-cleachdaidh dàta a ghineadh agus na liostaichean film aca fhèin a chruthachadh. Bidh an aplacaid a’ sàbhaladh agus ag ath-nuadhachadh dàta luchd-cleachdaidh.
Tha seallaidhean, co-phàirtean agus modailean air an sgaradh gu soilleir a’ cleachdadh pàtran Redux. Tha an sruth dàta an seo aon-stiùiridh. Faodar a làn thasgadh, ath-nuadhachadh agus ath-sgrìobhadh.
Bidh an aplacaid a’ cleachdadh na pàirtean bunaiteach de SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal, msaa. Bidh e cuideachd a’ toirt seachad seallaidhean àbhaisteach, gluasadan-bodhaig, UI / UX.
Gu dearbh, tha am beòthalachd rèidh, thionndaidh an GIF a-mach beagan borb
Thug a bhith ag obair air an aplacaid tòrr eòlas dhomh agus gu h-iomlan b’ e eòlas math a bh’ ann. Bha e comasach dhomh tagradh làn-ghnìomhach a sgrìobhadh, san t-Sultain leasaichidh mi e agus foillsichidh mi e san AppStore, aig an aon àm ri sgaoileadh iOS 13.
Redux, BindableObject agus EnvironmentObject
Tha mi air a bhith ag obair le Redux airson timcheall air dà bhliadhna a-nis, agus mar sin tha mi an ìre mhath eòlach air. Gu sònraichte, bidh mi ga chleachdadh san aghaidh airson React làrach-lìn, a bharrachd air a bhith a’ leasachadh iarrtasan dùthchasach iOS (Swift) agus Android (Kotlin).
Cha robh aithreachas orm a-riamh a bhith a’ taghadh Redux mar an ailtireachd sruthadh dàta airson tagradh SwiftUI a thogail. Is e na pàirtean as dùbhlanaiche nuair a bhios tu a ’cleachdadh Redux ann an app UIKit ag obair leis a’ bhùth agus a ’faighinn agus a’ faighinn dàta air ais agus ga mhapadh a rèir do bheachdan / co-phàirtean. Gus seo a dhèanamh, bha agam ri seòrsa de leabharlann de luchd-ceangail a chruthachadh (a’ cleachdadh ReSwift agus ReKotlin). Ag obair gu math, ach tòrr còd. Gu mì-fhortanach, chan eil e (fhathast) stòr fosgailte.
Deagh naidheachd! Is e na h-aon rudan a tha draghail mu dheidhinn SwiftUI - ma tha thu an dùil Redux a chleachdadh - stòran, stàitean, agus lughdachaidhean. Tha SwiftUI gu tur a’ toirt aire do eadar-obrachadh leis a’ bhùth le taing dha @EnvironmentObject. Mar sin, bidh stòr a’ tòiseachadh le BindableObject.
Chruthaich mi pasgan Swift sìmplidh, SwiftUIFlux, a bheir seachad cleachdadh bunaiteach de Redux. Anns a’ chùis agam tha e na phàirt de MovieSwiftUI. Mise cuideachd sgrìobh oideachadh ceum air cheum, a chuidicheas tu gus am pàirt seo a chleachdadh.
Ciamar a dh'obraicheas e?
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 bhrosnaicheas tu gnìomh, cuiridh tu am bogsa gèar an gnìomh. Nì e measadh air gnìomhan a rèir staid làithreach an tagraidh. Tillidh e an uairsin stàite atharraichte ùr a rèir an seòrsa gnìomh agus an dàta.
Uill, leis gur e BindableObject a th’ ann an stòr, cuiridh e fios gu SwiftUI nuair a dh’ atharraicheas a luach a’ cleachdadh an t-seilbh willChange a thug PassthroughSubject seachad. Tha seo air sgàth gu feum am BindableObject PublisherType a thoirt seachad, ach tha e an urra ri buileachadh a’ phròtacal a riaghladh. Gu h-iomlan, is e inneal fìor chumhachdach a tha seo bho Apple. Mar sin, anns an ath chearcall tairgse, cuidichidh SwiftUI le bhith a’ toirt seachad na beachdan a rèir atharrachadh na stàite.
Gu fìrinneach, is e seo cridhe agus draoidheachd SwiftUI. A-nis, ann an sealladh sam bith a tha fo-sgrìobhadh do stàit, thèid an sealladh a thoirt seachad a rèir dè an dàta a gheibhear bhon stàit agus na tha air atharrachadh.
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())
}
}
Tha an Stòr air a thoirt a-steach mar EnvironmentObject nuair a thòisicheas an tagradh agus an uairsin gheibhear thuige ann an sealladh sam bith a’ cleachdadh @EnvironmentObject. Chan eil peanas coileanaidh ann leis gu bheil togalaichean a thàinig às a’ faighinn air ais gu sgiobalta no air an tomhas bho staid an tagraidh.
Bidh an còd gu h-àrd ag atharrachadh an ìomhaigh ma dh'atharraicheas am postair film.
Agus tha seo air a dhèanamh le dìreach aon loidhne, le cuideachadh bho na beachdan a tha ceangailte ris an stàit. Ma tha thu air a bhith ag obair le ReSwift air iOS no eadhon ceangal le React, tuigidh tu draoidheachd SwiftUI.
A-nis faodaidh tu feuchainn ris a’ ghnìomh a chuir an gnìomh agus an stàit ùr fhoillseachadh. Seo eisimpleir nas iom-fhillte.
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!]))
}
}
}
}
Anns a 'chòd gu h-àrd, tha mi a' cleachdadh an gnìomh .onDelete bho SwiftUI airson gach IP. Leigidh seo leis an loidhne san liosta an swipe àbhaisteach iOS a thaisbeanadh airson a sguabadh às. Mar sin nuair a chuireas an neach-cleachdaidh suathadh air a’ phutan cuir às, bidh e a’ piobrachadh a’ ghnìomh fhreagarrach agus a’ toirt air falbh am film bhon liosta.
Uill, leis gu bheil seilbh an liosta a’ tighinn bhon stàit BindableObject agus air a thoirt a-steach mar EnvironmentObject, bidh SwiftUI ag ùrachadh an liosta leis gu bheil ForEach co-cheangailte ri seilbh àireamhaichte nam filmichean.
Seo pàirt den lughdadair 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
}
Thèid an lughdadair a chuir gu bàs nuair a chuireas tu gnìomh air falbh agus nuair a thilleas tu stàite ùr, mar a chaidh a ràdh gu h-àrd.
Cha tèid mi a-steach gu mion-fhiosrachadh fhathast - mar a tha fios aig SwiftUI dha-rìribh dè a thaisbeanadh. Gus seo a thuigsinn nas doimhne, is fhiach e faic seisean WWDC air sruthadh dàta ann an SwiftUI. Tha e cuideachd a’ mìneachadh gu mionaideach carson agus cuin a bu chòir a chleachdadh Stàite, @Binding, ObjectBinding agus EnvironmentObject.