
Pas një pjesëmarrjeje në sesionin State of the Union në WWDC 2019, vendosa të studioj në detaje SwiftUI. Kam shpenzuar shumë kohë duke punuar me të dhe tani kam filluar të zhvilloj një aplikacion real që mund të jetë i dobishëm për një gamë të gjerë përdoruesish.
E quajta MovieSwiftUI â Ă«shtĂ« njĂ« aplikacion pĂ«r tĂ« kĂ«rkuar filma tĂ« rinj dhe tĂ« vjetĂ«r, si dhe pĂ«r t'i mbledhur ata nĂ« njĂ« koleksion duke pĂ«rdorur . Kam dashur gjithmonĂ« filmat dhe madje krijova njĂ« kompani qĂ« punonte nĂ« kĂ«tĂ« fushĂ«, edhe pse para njĂ« kohe. Kompania ishte e vĂ«shtirĂ« tĂ« quhej e shkĂ«lqyer, por aplikacioni Ă«shtĂ« sigurisht!
KujtojmĂ«: pĂ«r tĂ« gjithĂ« lexuesit e "Habra" â zbritje prej 10,000 rublej pĂ«r regjistrimin nĂ« çdo kurs Skillbox me kodin promocional "Habr".
Skillbox rekomandon: Kurs online edukativ .
Pra, çfarë mund të bëjë MovieSwiftUI?
- NdĂ«rvepron me API â kjo Ă«shtĂ« diçka qĂ« pothuajse çdo aplikacion modern e bĂ«n.
- Ngarkon të dhëna asinkrone sipas kërkesave dhe përpunon JSON në modelet Swift, duke përdorur .
- Tregon imazhe që ngarkohen sipas kërkesës dhe i ruan ato në memorje.
- Ky aplikacion për iOS, iPadOS, dhe macOS ofron një përvojë të shkëlqyer për përdoruesit e këtyre sistemeve operative.
- Përdoruesi mund të gjenerojë të dhëna dhe të krijojë lista filmash vetë. Aplikacioni ruan dhe rikthen të dhënat e përdoruesve.
- Pamjet, komponentët dhe modelet janë qartë të ndara duke përdorur modelin Redux. Fluksi i të dhënave këtu është njëdrejtues. Ai mund të ruhet plotësisht, të rikthehet dhe të rishkruhet.
- Aplikacioni përdor komponentët bazë të SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal etj. Gjithashtu, ai ofron pamje të personalizuara, gjeste, UI/UX.

Në të vërtetë animacioni është i qetë, por gif-i doli pak i shqetësuar.
Puna mbi aplikacionin më dha shumë përvojë, dhe në përgjithësi ishte një përvojë pozitive. Arrita të shkruaj një aplikacion me funksionalitet të plotë, dhe në shtator do ta përmirësoj dhe do ta publikoj në AppStore, njëkohësisht me daljen e iOS 13.
Redux, BindableObject dhe EnvironmentObject

Aktualisht kam punuar me Redux për rreth dy vjet, kështu që jam relativisht mirë në të. Në veçanti, e përdor atë në front-end për faqen e internetit, si dhe për zhvillimin e aplikacioneve natyrore për iOS (Swift) dhe Android (Kotlin).
Nuk kam penduar asnjëherë për zgjedhjen e Redux si arkitekturën e flux-it të të dhënave për krijimin e aplikacionit në SwiftUI. Pikat më të ndërlikuara kur punoni me Redux në aplikacionin UIKit janë puna me store-in, si dhe marrja dhe nxjerrja e të dhënave dhe përputhja e tyre me pamjet tuaja / komponentët. Për këtë, pata nevojë të krijoja një lloj biblioteke lidhësish (në ReSwift dhe ReKotlin). Punohet mirë, por ka mjaft kod. Fatkeqësisht, ai (për momentin) nuk është open source.
Lajme tĂ« mira! E vetmja gjĂ« pĂ«r tĂ« cilĂ«n duhet tĂ« shqetĂ«soheni me SwiftUI â nĂ«se planifikoni tĂ« pĂ«rdorni Redux â Ă«shtĂ« store, gjendjet dhe reduktorĂ«t. NdĂ«rveprimi me store-in merr pĂ«rsipĂ«r plotĂ«sisht SwiftUI falĂ« @EnvironmentObject. Pra, store fillon me BindableObject.
Kam krijuar një paketë të thjeshtë Swift, , e cila ofron përdorim bazik të Redux. Në rastin tim, kjo është një pjesë e MovieSwiftUI. Gjithashtu, unë , i cili do të ndihmojë në përdorimin e këtij komponenti.
Si funksionon?
final public class Store: BindableObject {
public let willChange = PassthroughSubject()
private(set) public var state: State
private func _dispatch(action: Action) {
willChange.send()
state = reducer(state, action)
}
}Ădo herĂ« qĂ« aktivizoni njĂ« veprim, aktivizoni reduktorin. Ai do tĂ« vlerĂ«sojĂ« veprimet sipas gjendjes aktuale tĂ« aplikacionit. MĂ« pas ai do tĂ« kthejĂ« njĂ« gjendje tĂ« re tĂ« modifikuar sipas llojit tĂ« veprimit dhe tĂ« dhĂ«nave.
Dhe pasi store-i është BindableObject, ai do të njoftojë SwiftUI për ndryshimin e vlerës së tij, duke përdorur pronën willChange, të ofruar nga PassthroughSubject. Kjo është sepse BindableObject duhet të ofrojë PublisherType, por implementimi i protokollit është përgjegjës për menaxhimin e tij. Në përgjithësi, ky është një mjet shumë i fuqishëm nga Apple. Për pasojë, në ciklin e ardhshëm të renderimit, SwiftUI do të ndihmojë në shfaqjen e trupit të pamjeve sipas ndryshimit të gjendjes.
NĂ« fakt, kjo Ă«shtĂ« e gjitha â zemra dhe magia e SwiftUI. Tani nĂ« çdo pamje qĂ« Ă«shtĂ« e regjistruar nĂ« gjendje, pamja do tĂ« shfaqet sipas tĂ« dhĂ«nave qĂ« merren nga gjendja dhe asaj qĂ« ka ndryshuar.
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
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())
}
}Magazina integron si EnvironmentObject gjatë nisjes së aplikacionit, dhe pastaj është i disponueshëm në çdo pamje përmes @EnvironmentObject. Performanca nuk bie, pasi pronat e derivuara nxirren ose llogariten shpejt nga gjendja e aplikacionit.
Kodi që përmendet më lart ndron imazhin nëse posteri i filmit ndryshon.
Dhe kjo ndodh në fakt vetëm me një rresht, me anë të të cilit lidhen pamjet me gjendjen. Nëse keni punuar me ReSwift në iOS ose madje me React, do ta kuptoni se cila është magjia e SwiftUI.
Tani mund të provoni të aktivizoni veprimin dhe të publikoni një gjendje të re. Ja një shembull më të komplikuar.
struct CustomListDetail : View {
@EnvironmentObject var store: Store
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!]))
}
}
}
}Në kodin më lart, përdor veprimin .onDelete nga SwiftUI për secilin IP. Kjo lejon që rreshti në listë të tregojë lëvizjen e zakonshme të fshirjes në iOS. Prandaj, kur përdoruesi preku butonin e fshirjes, ai aktivizon veprimin përkatës dhe fshin filmin nga lista.
Dhe për sa kohë që prona e listës është një pronë e derivuar nga BindableObject dhe integrot si EnvironmentObject, atëherë SwiftUI përditëson listën, sepse ForEach është lidhur me pronën e llogaritur movies.
Ja një pjesë e reduktorit MoviesState:
func moviesStateReducer(state: MoviesState, action: Action) -> MoviesState {
var state = state
switch action {
// veprime të tjera.
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
}Reduktori ekzekutohet kur dërgoni një veprim dhe kthemi një gjendje të re, siç është thënë më lart.
Nuk do tĂ« hyj nĂ« detaje tani â se si SwiftUI e di me tĂ« vĂ«rtetĂ« se çfarĂ« tĂ« tregojĂ«. PĂ«r tĂ« kuptuar kĂ«tĂ« mĂ« thellĂ«, ia vlen nĂ« SwiftUI. Aty po ashtu sqarohet pĂ«rse dhe kur tĂ« pĂ«rdorni , @Binding, ObjectBinding dhe EnvironmentObject.
Skillbox rekomandon:
- Kurs praktik .
- Kursi online i aplikimit .
- Kurs praktik dyvjeçar .
Burimi: habr.com
