
Pas pasjes së seancës State of the Union në WWDC 2019, vendosa të shqyrtoj me kujdes SwiftUI. Kam kaluar shumë kohë duke punuar me të dhe tani kam filluar zhvillimin e një aplikacioni real që mund të jetë i dobishëm për një gamë të gjerë përdoruesish.
E quajta MovieSwiftUI â ky Ă«shtĂ« njĂ« aplikacion pĂ«r kĂ«rkimin e filmave tĂ« rinj dhe tĂ« vjetĂ«r, si dhe pĂ«r grumbullimin e tyre nĂ« koleksion pĂ«rmes . Kam dashur gjithmonĂ« filmat dhe madje kam krijuar njĂ« kompani qĂ« punon nĂ« kĂ«tĂ« fushĂ«, megjithatĂ«, kjo ka ndodhur njĂ« kohĂ« tĂ« gjatĂ«. Kompania ishte e vĂ«shtirĂ« pĂ«r t'u quajtur e shkĂ«lqyer, por aplikacioni, po!
KujtojmĂ«: pĂ«r tĂ« gjithĂ« lexuesit e «Habra» â zbritje prej 10,000 rublesh pĂ«r regjistrimin nĂ« çdo kurs Skillbox me kodin promovues «Habr».
Skillbox rekomandon: Kurs online edukativ .
Pra, çfarë mund të bëjë MovieSwiftUI?
- NdĂ«rvepron me API â kjo e bĂ«n pothuajse çdo aplikacion modern.
- Shkarkon të dhëna asinkrone përmes kërkesave dhe analizojnë JSON në modele Swift, duke përdorur .
- Tregon imazhe që shkarkohen sipas kërkesës dhe i ruan ato.
- Ky aplikacion për iOS, iPadOS dhe macOS ofron përvojën më të mirë të përdoruesve të këtyre sistemeve operative.
- Përdoruesi mund të gjenerojë të dhëna, të krijojë lista të tij të filmave. Aplikacioni ruan dhe rikthen të dhënat e përdoruesit.
- Pamjet, komponentët dhe modelet janë ndarë qartë duke përdorur modelin Redux. Rryma e të dhënave këtu është një drejtim. Ajo mund të ruhet, rikthehet dhe shkruhet përsëri plotësisht.
- Aplikacioni përdor komponentë të bazuar në SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal etj. Ai gjithashtu ofron pamje të personalizuara, gjeste, UI/UX.

Në të vërtetë, animacioni është i qetë, GIF-i doli pak i çrregullt.
Puna mbi aplikacionin më dha shumë përvojë, dhe në përgjithësi, kjo është një përvojë pozitive. Arrita të shkruaj një aplikacion me funksionalitet të plotë, në Shtator do ta përmirësoj dhe do ta publikoj në AppStore, në të njëjtën kohë me lansimin e iOS 13.
Redux, BindableObject dhe EnvironmentObject

Në këtë moment, kam punuar me Redux për rreth dy vjet, kështu që kam një njohuri të mirë për të. Në veçanti, e përdor atë në frontend për uebfaqen, si dhe për zhvillimin e aplikacioneve natyrore iOS (Swift) dhe Android (Kotlin).
Nuk kam penduar asnjëherë për zgjedhjen e Redux si arkitekturë për rrjedhën e të dhënave për krijimin e një aplikacioni në SwiftUI. Momentet më sfiduese kur përdorni Redux në aplikacionin UIKit janë menaxhimi i store-it, si dhe marrja dhe nxjerrja e të dhënave dhe përputhja e tyre me pamjet tuaja / komponentët. Për këtë, duhej të krijoja një lloj biblioteke konnektorësh (në ReSwift dhe ReKotlin). Punon mirë, por ka mjaft kod. Fatkeqësisht, ai (deri tani) 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 reduktuesit. Interaksioni me store-in merret plotĂ«sisht pĂ«rsipĂ«r nga SwiftUI pĂ«rmes @EnvironmentObject. KĂ«shtu, 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 ndihmon në përdorimin e këtij komponenti.
Si funksionon kjo?
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Ă« ekzekutoni njĂ« veprim, aktivizoni reduktorin. Ai do tĂ« vlerĂ«sojĂ« veprimet nĂ« pĂ«rputhje me gjendjen aktuale tĂ« aplikacionit. MĂ« pas, ai do tĂ« kthejĂ« njĂ« gjendje tĂ« re tĂ« modifikuar nĂ« pĂ«rputhje me llojin e veprimit dhe tĂ« dhĂ«nat.
Dhe sepse store është një BindableObject, ai do ta njoftojë SwiftUI për ndryshimin e vlerës së tij, duke përdorur pronën willChange, e cila ofrohet nga PassthroughSubject. Kjo ndodh 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. Në përputhje, në ciklin e ardhshëm të renderimit, SwiftUI do të ndihmojë në shfaqjen e trupit të pamjeve në përputhje me ndryshimin e gjendjes.
Pra, ky është thelbi dhe magia e SwiftUI. Tani në çdo pamje që është e nënshkruar për gjendjen, pamja do të shfaqet në përputhje me të dhënat që merren nga gjendja dhe çfarë 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())
}
}Store është integruar si EnvironmentObject gjatë nisjes së aplikacionit, dhe më pas është e aksesueshme në çdo pamje përmes @EnvironmentObject. Performanca nuk zvogëlohet, pasi pronat e nxjerra janë shpejt të nxjerra ose të llogaritura nga gjendja e aplikacionit.
Kodi i mësiperm ndryshon imazhin nëse poster-i i filmit ndryshon.
Dhe kjo bëhet në fakt me vetëm një rresht, i cili lidh pamjet me gjendjen. Nëse keni punuar me ReSwift në iOS ose madje me React, do të kuptoni se çfarë është magjia e SwiftUI.
Tani mund të provoni të aktivizoni një veprim dhe të publikoni një gjendje të re. Ky është një shembull më i ndërlikuar.
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 e mësipërm, unë përdor veprimin .onDelete nga SwiftUI për çdo IP. Kjo lejon që një rresht në listë të tregojë një tërheqje të zakonshme iOS për përjashtim. Kështu, kur përdoruesi prek butonin e fshirjes, ai aktivizon veprimin përkatës dhe heq filmin nga lista.
Dhe, duke qenë se prona e listës është johumbur nga gjendja e BindableObject dhe implementohet si EnvironmentObject, SwiftUI azhurnon listën, pasi ForEach është i lidhur me pronën e llogaritur movies.
Këtu është një pjesë e reduktorit 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
}Reduktori ekzekutohet kur ju dërgoni një veprim dhe kthen një gjendje të re, siç u tha më lart.
Nuk do tĂ« hyj nĂ« detaje pĂ«r momentin â nga e di SwiftUI se çfarĂ« tĂ« shfaqĂ«. PĂ«r ta kuptuar kĂ«tĂ« mĂ« thellĂ«, Ă«shtĂ« e dobishme nĂ« SwiftUI. Gjithashtu aty shpjegohet nĂ« detaje pse dhe kur tĂ« pĂ«rdorni , @Binding, ObjectBinding dhe EnvironmentObject.
Skillbox rekomandon:
- Kurs praktik .
- Kurs online aplikativ .
- Kursi praktik dyvjeçar .
Burimi: habr.com
