نظارو، اجزاء ۽ ماڊل واضح طور تي Redux نموني استعمال ڪندي جدا ڪيا ويا آهن. هتي ڊيٽا جو وهڪرو اڻ سڌي آهي. اهو مڪمل طور تي ڪيش، بحال ۽ اوور رائٽ ٿي سگهي ٿو.
ايپ تي ڪم ڪرڻ مون کي تمام گهڻو تجربو ڏنو ۽ مجموعي طور تي اهو هڪ مثبت تجربو هو. مان هڪ مڪمل فنڪشنل ايپليڪيشن لکڻ جي قابل ٿيس، سيپٽمبر ۾ آئون ان کي بهتر ڪندس ۽ ايپ اسٽور ۾ شايع ڪندس، انهي سان گڏ iOS 13 جي رليز سان.
Redux، BindableObject ۽ EnvironmentObject
مان هاڻي تقريباً ٻن سالن کان ريڊڪس سان ڪم ڪري رهيو آهيان، تنهن ڪري مان ان ۾ نسبتاً چڱيءَ طرح واقف آهيان. خاص طور تي، مان ان کي فرنٽ اينڊ ۾ استعمال ڪريان ٿو تصديق ڪريو ويب سائيٽ، انهي سان گڏ مقامي iOS (Swift) ۽ Android (Kotlin) ايپليڪيشنن کي ترقي ڪرڻ لاء.
مون ڪڏهن به ريڊڪس کي چونڊڻ تي افسوس نه ڪيو آهي جيئن هڪ SwiftUI ايپليڪيشن ٺاهڻ لاءِ ڊيٽا فلو آرڪيٽيڪچر. UIKit ايپ ۾ ريڊڪس استعمال ڪرڻ وقت سڀ کان وڌيڪ مشڪل حصا اسٽور سان ڪم ڪري رهيا آهن ۽ ڊيٽا حاصل ڪرڻ ۽ حاصل ڪرڻ ۽ ان کي توهان جي نظرن/جزائن تي نقشي ڪرڻ. هن کي ڪرڻ لاء، مون کي ڪنيڪٽرن جي هڪ قسم جي لائبريري ٺاهي هئي (استعمال ڪندي ReSwift ۽ ReKotlin). سٺو ڪم ڪري ٿو، پر ڪافي ڪوڊ. بدقسمتي سان، اهو نه آهي (اڃا تائين) کليل ذريعو.
سٺي خبر! SwiftUI سان پريشان ٿيڻ لاءِ صرف شيون - جيڪڏهن توهان ريڊڪس استعمال ڪرڻ جو ارادو ڪيو ٿا - اسٽور آهن ، رياستون ۽ گهٽتائي ڪندڙ. اسٽور سان تعامل مڪمل طور تي سنڀاليو ويو آهي SwiftUI جي مهرباني @EnvironmentObject. تنهن ڪري، اسٽور شروع ٿئي ٿو BindableObject سان.
مون هڪ سادي سوفٹ پيڪيج ٺاهيو، SwiftUIFlux، جيڪو Redux جو بنيادي استعمال مهيا ڪري ٿو. منهنجي صورت ۾ اهو حصو آهي MovieSwiftUI. مان پڻ هڪ قدم قدم سبق لکيو، جيڪو توهان کي هن جزو کي استعمال ڪرڻ ۾ مدد ڏيندو.
ان کي ڪيئن ڪم ڪندو؟
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)
}
}
هر دفعي توهان هڪ عمل کي ٽاريندا آهيو، توهان گيرو باڪس کي چالو ڪيو. اهو ايپليڪيشن جي موجوده حالت جي مطابق عملن جو جائزو وٺندو. اهو وري عمل جي قسم ۽ ڊيٽا جي مطابق هڪ نئين تبديل ٿيل رياست واپس ڪندو.
خير، جيئن ته اسٽور هڪ BindableObject آهي، اهو SwiftUI کي اطلاع ڏيندو جڏهن ان جي قيمت تبديل ٿي ويندي استعمال ڪندي وِل چَنج پراپرٽي PassthroughSubject پاران مهيا ڪيل. اهو ئي سبب آهي ته BindableObject هڪ PublisherType مهيا ڪرڻ گهرجي، پر پروٽوڪول تي عمل درآمد ان کي منظم ڪرڻ جو ذميوار آهي. مجموعي طور تي، هي ايپل کان هڪ تمام طاقتور اوزار آهي. ان جي مطابق، ايندڙ رينڊنگ چڪر ۾، SwiftUI رياست جي تبديلي جي مطابق نظرن جي جسم کي رينجر ڪرڻ ۾ مدد ڪندي.
دراصل، هي سڀ دل ۽ جادو آهي SwiftUI جو. هاڻي، ڪنهن به نظريي ۾ جيڪو ڪنهن رياست جي رڪنيت حاصل ڪري ٿو، اهو نظريو بيان ڪيو ويندو ته رياست کان ڪهڙي ڊيٽا حاصل ڪئي وئي آهي ۽ ڪهڙي تبديلي آئي آهي.
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())
}
}
اسٽور کي هڪ EnvironmentObject طور انجيڪشن ڪيو ويندو آهي جڏهن ايپليڪيشن شروع ٿئي ٿي ۽ پوءِ @EnvironmentObject استعمال ڪندي ڪنهن به ڏيک ۾ رسائي لائق آهي. ڪارڪردگي جي ڪا به سزا نه آهي ڇو ته نڪتل ملڪيتون جلدي حاصل ڪيون وينديون آهن يا ايپليڪيشن اسٽيٽ مان ڳڻپيو وينديون آهن.
مٿي ڏنل ڪوڊ تصوير کي تبديل ڪري ٿو جيڪڏهن فلم پوسٽر تبديل ٿي وڃي.
۽ اهو اصل ۾ صرف هڪ لڪير سان ڪيو ويو آهي، جنهن جي مدد سان نظريا رياست سان ڳنڍيل آهن. جيڪڏهن توهان iOS تي ReSwift سان ڪم ڪيو آهي يا اڃا به سان ڳنڍڻ React سان، توهان SwiftUI جو جادو سمجھندا.
ھاڻي توھان ڪوشش ڪري سگھوٿا عمل کي چالو ڪرڻ ۽ نئين رياست کي شايع ڪرڻ. هتي هڪ وڌيڪ پيچيده مثال آهي.
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!]))
}
}
}
}
مٿي ڏنل ڪوڊ ۾ مان استعمال ڪري رهيو آهيان .onDelete عمل SwiftUI کان هر IP لاءِ. هي فهرست ۾ قطار کي حذف ڪرڻ لاءِ عام iOS سوائپ ڏيکاري ٿو. تنهن ڪري جڏهن صارف حذف ڪرڻ واري بٽڻ کي ڇڪي ٿو، اهو لاڳاپيل عمل کي متحرڪ ڪري ٿو ۽ فلم کي فهرست مان هٽائي ٿو.
خير، جيئن ته لسٽ جي ملڪيت BindableObject رياست مان نڪتل آهي ۽ هڪ EnvironmentObject جي طور تي انجيل آهي، SwiftUI لسٽ کي اپڊيٽ ڪري ٿو ڇو ته ForEach فلمن جي حساب سان ملڪيت سان لاڳاپيل آهي.
هتي فلم اسٽيٽ ريڊيسر جو حصو آهي:
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
}