Hoʻomohala noi ma SwiftUI. Mahele 1: Dataflow a me Redux
Ma hope o ka hele ʻana i ka hui State of the Union ma WWDC 2019, ua hoʻoholo wau e lawe i kahi luʻu hohonu i SwiftUI. Ua hoʻohana au i ka manawa nui me ia a ua hoʻomaka wau e hoʻomohala i kahi noi maoli e hiki ke hoʻohana i nā mea hoʻohana ākea.
Ua kapa au iā ia ʻo MovieSwiftUI - he polokalamu kēia no ka ʻimi ʻana i nā kiʻiʻoniʻoni hou a me nā kiʻiʻoniʻoni kahiko, a me ka hōʻiliʻili ʻana iā lākou i kahi hōʻiliʻili hoʻohana. API TMDB. Ua makemake mau au i nā kiʻiʻoniʻoni a ua hoʻokumu i kahi ʻoihana e hana ana ma kēia kahua, ʻoiai he wā lōʻihi ma mua. ʻAʻole hiki ke kapa ʻia ka hui ʻoluʻolu, akā ʻo ka noi!
Hoʻomaopopo mākou iā ʻoe:no ka poʻe heluhelu a pau o "Habr" - kahi ho'ēmi o 10 rubles i ka wā e kākau inoa ai i kekahi papa Skillbox e hoʻohana ana i ka code promotional "Habr".
Hoʻopili me ka API - kokoke i nā noi hou e hana i kēia.
Hoʻouka i ka ʻikepili asynchronous ma nā noi a hoʻopau iā JSON i ka hoʻohālike Swift me ka hoʻohana ʻana Codable.
Hōʻike i nā kiʻi i hoʻouka ʻia ma ke noi a hūnā iā lākou.
Hāʻawi kēia polokalamu no iOS, iPadOS, a me macOS i ka UX maikaʻi loa no nā mea hoʻohana o kēia mau OS.
Hiki i ka mea hoʻohana ke hana i ka ʻikepili a hana i kā lākou papa inoa kiʻiʻoniʻoni ponoʻī. Mālama ka polokalamu a hoʻihoʻi i ka ʻikepili mea hoʻohana.
Hoʻokaʻawale ʻia nā hiʻohiʻona, nā ʻāpana a me nā hiʻohiʻona me ka hoʻohana ʻana i ke ʻano Redux. ʻO ke kahe ʻikepili ma ʻaneʻi he unidirectional. Hiki ke hoʻopaʻa ʻia, hoʻihoʻi ʻia a kākau ʻia.
Hoʻohana ka noi i nā ʻāpana kumu o SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal, etc. Hāʻawi pū ia i nā hiʻohiʻona maʻamau, nā hana, UI / UX.
ʻO kaʻoiaʻiʻo, ua maʻalahi ka animation, ua hoʻololi iki ka GIF
ʻO ka hana ʻana ma ka app ua hāʻawi mai iaʻu i ka ʻike he nui a ʻo ka holoʻokoʻa he ʻike maikaʻi. Ua hiki iaʻu ke kākau i kahi noi hana holoʻokoʻa, i ka mahina ʻo Kepakemapa e hoʻomaikaʻi wau a hoʻolaha iā ia ma ka AppStore, i ka manawa like me ka hoʻokuʻu ʻana o iOS 13.
Redux, BindableObject a me EnvironmentObject
Ua hana au me Redux no ʻelua mau makahiki i kēia manawa, no laila ua ʻike maikaʻi wau i ia mea. Ma keʻano kūikawā, hoʻohana wau ia ma ka frontend no pane koke pūnaewele, a me ka hoʻomohala ʻana i nā polokalamu iOS (Swift) a me Android (Kotlin).
ʻAʻole loa au i mihi i ke koho ʻana iā Redux ma ke ʻano he hoʻolālā kahe data no ke kūkulu ʻana i kahi noi SwiftUI. ʻO nā ʻāpana paʻakikī loa i ka hoʻohana ʻana iā Redux i kahi noi UIKit e hana pū ana me ka hale kūʻai a loaʻa a kiʻi hou i ka ʻikepili a hoʻopaʻa ʻia i kāu mau manaʻo / ʻāpana. No ka hana ʻana i kēia, pono wau e hana i kahi ʻano waihona o nā mea hoʻohui (me ka hoʻohana ʻana iā ReSwift a me ReKotlin). Hana maikaʻi, akā nui ka code. ʻO ka mea pōʻino, ʻaʻole ia (a) i wehe i ke kumu.
Nuhou maikaʻi! ʻO nā mea wale nō e hopohopo ai me SwiftUI - inā ʻoe e hoʻolālā e hoʻohana iā Redux - nā hale kūʻai, mokuʻāina, a me nā mea hoʻemi. Mālama ʻia ka pilina me ka hale kūʻai e SwiftUI mahalo iā @EnvironmentObject. No laila, hoʻomaka ka hale kūʻai me kahi BindableObject.
Ua hana au i kahi pōkole Swift maʻalahi, SwiftUIFlux, e hāʻawi ana i ka hoʻohana maʻamau o Redux. I koʻu hihia he ʻāpana ia o MovieSwiftUI. ʻo wau kekahi ua kākau i kahi aʻo ʻanuʻu, e kōkua iā ʻoe e hoʻohana i kēia ʻāpana.
Pehea ia hana?
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)
}
}
I kēlā me kēia manawa ke hoʻomaka ʻoe i kahi hana, hoʻāla ʻoe i ka pahu pahu. E loiloi ia i nā hana e like me ke kūlana o kēia manawa o ka noi. E hoʻihoʻi ia i kahi mokuʻāina hou i hoʻololi ʻia e like me ke ʻano hana a me ka ʻikepili.
ʻAe, no ka mea he BindableObject ka hale kūʻai, e hoʻomaopopo ʻo ia iā SwiftUI i ka wā e loli ai kona waiwai me ka hoʻohana ʻana i ka waiwai willChange i hāʻawi ʻia e PassthroughSubject. ʻO kēia no ka mea pono e hāʻawi ka BindableObject i kahi PublisherType, akā ʻo ka hoʻokō protocol ke kuleana no ka mālama ʻana. Ma keʻano holoʻokoʻa, he mea hana ikaika loa kēia mai Apple. No laila, i ke kaʻina hana e hiki mai ana, e kōkua ʻo SwiftUI i ke kino o nā manaʻo e like me ka loli mokuʻāina.
ʻOiaʻiʻo, ʻo kēia ka puʻuwai a me ke kilokilo o SwiftUI. I kēia manawa, i kēlā me kēia manaʻo e kau inoa i kahi mokuʻāina, e hāʻawi ʻia ka ʻike e like me ka ʻikepili i loaʻa mai ka mokuʻāina a me nā mea i loli.
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())
}
}
Hoʻokomo ʻia ka hale kūʻai ma ke ʻano he EnvironmentObject i ka wā e hoʻomaka ai ka noi a laila hiki ke ʻike ʻia i kekahi ʻike me ka hoʻohana ʻana @EnvironmentObject. ʻAʻohe hoʻopaʻi hoʻokō no ka mea e kiʻi koke ʻia nā waiwai i loaʻa a helu ʻia mai ke kūlana noi.
Hoʻololi ke code ma luna i ke kiʻi inā hoʻololi ka pepa kiʻiʻoniʻoni.
A ua hana maoli ʻia kēia me ka laina hoʻokahi, me ke kōkua o nā manaʻo e pili ana i ka mokuʻāina. Inā ʻoe i hana pū me ReSwift ma iOS a i ʻole hoʻohui me React, e hoʻomaopopo ʻoe i ke kilokilo o SwiftUI.
I kēia manawa hiki iā ʻoe ke hoʻāʻo e hoʻāla i ka hana a hoʻolaha i ka mokuʻāina hou. Eia kekahi laʻana paʻakikī.
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!]))
}
}
}
}
Ma ke code ma luna, ke hoʻohana nei au i ka hana .onDelete mai SwiftUI no kēlā me kēia IP. ʻAe kēia i ka lālani i ka papa inoa e hōʻike i ka swipe maʻamau o iOS e holoi. No laila ke hoʻopā ka mea hoʻohana i ka pihi holoi, hoʻomaka ia i ka hana kūpono a wehe i ke kiʻiʻoniʻoni mai ka papa inoa.
Ma muli o ka loaʻa ʻana o ka waiwai papa inoa mai ka mokuʻāina ʻo BindableObject a ua hoʻokomo ʻia ma ke ʻano he EnvironmentObject, ua hōʻano hou ʻo SwiftUI i ka papa inoa no ka mea pili ʻo ForEach me nā kiʻiʻoniʻoni i helu ʻia.
Eia kahi ʻāpana o ka 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
}
Hoʻokō ʻia ka mea hoʻemi ke hoʻouna ʻoe i kahi hana a hoʻihoʻi i kahi mokuʻāina hou, e like me ka ʻōlelo ma luna.
ʻAʻole wau e hele i nā kikoʻī - pehea e ʻike maoli ai ʻo SwiftUI i ka mea e hōʻike ai. No ka hoʻomaopopo hohonu ʻana i kēia, pono ia e nānā i ke kau WWDC ma ke kahe ʻikepili ma SwiftUI. E wehewehe ana i ke kumu a me ka wā e hoʻohana ai Moku'āina, @Binding, ObjectBinding a me EnvironmentObject.