SwiftUI تي ايپليڪيشن ڊولپمينٽ. حصو 1: ڊيٽا فلو ۽ ريڊڪس

SwiftUI تي ايپليڪيشن ڊولپمينٽ. حصو 1: ڊيٽا فلو ۽ ريڊڪس

WWDC 2019 ۾ اسٽيٽ آف دي يونين سيشن ۾ شرڪت ڪرڻ کان پوءِ، مون فيصلو ڪيو ته SwiftUI ۾ گہرا غوطا ھڻي. مون ان سان گڏ ڪم ڪرڻ ۾ گھڻو وقت گذاريو آھي ۽ ھاڻي ھڪڙي حقيقي ايپليڪيشن تيار ڪرڻ شروع ڪئي آھي جيڪا صارفين جي وسيع رينج لاءِ ڪارآمد ٿي سگھي ٿي.

مون ان کي سڏيو آهي MovieSwiftUI - هي نئين ۽ پراڻي فلمون ڳولڻ لاءِ هڪ ايپ آهي، انهي سان گڏ انهن کي گڏ ڪرڻ لاءِ TMDB API. مون هميشه فلمن سان پيار ڪيو آهي ۽ ان شعبي ۾ ڪم ڪندڙ هڪ ڪمپني پڻ ٺاهي آهي، جيتوڻيڪ گهڻو وقت اڳ. ڪمپني کي شايد ئي ٿڌو سڏيو وڃي، پر ايپليڪيشن هئي!

اسان توهان کي ياد ڏياريون ٿا: "Habr" جي سڀني پڙهندڙن لاءِ - 10 روبل جي رعايت جڏهن "Habr" پروموشنل ڪوڊ استعمال ڪندي ڪنهن به اسڪل باڪس ڪورس ۾ داخلا.

Skillbox سفارش ڪري ٿو: تعليمي آن لائين ڪورس "پروفيشنل جاوا ڊولپر".

پوء ڇا ڪري سگھي ٿو MovieSwiftUI؟

  • API سان رابطو ڪري ٿو - تقريبن ڪنهن به جديد ايپليڪيشن اهو ڪري ٿو.
  • درخواستن تي غير مطابقت واري ڊيٽا لوڊ ڪري ٿو ۽ JSON کي استعمال ڪندي Swift ماڊل ۾ پارس ڪري ٿو ڪوڊ لائق.
  • درخواست تي لوڊ ڪيل تصويرون ڏيکاري ٿو ۽ انهن کي ڪيش ڪري ٿو.
  • هي ايپ iOS، iPadOS، ۽ macOS لاءِ انهن او ايس جي استعمال ڪندڙن لاءِ بهترين UX مهيا ڪري ٿي.
  • صارف ڊيٽا ٺاهي ۽ پنهنجون فلمون لسٽون ٺاهي سگھي ٿو. ايپليڪيشن محفوظ ڪري ٿي ۽ صارف جي ڊيٽا کي بحال ڪري ٿي.
  • نظارو، اجزاء ۽ ماڊل واضح طور تي Redux نموني استعمال ڪندي جدا ڪيا ويا آهن. هتي ڊيٽا جو وهڪرو اڻ سڌي آهي. اهو مڪمل طور تي ڪيش، بحال ۽ اوور رائٽ ٿي سگهي ٿو.
  • ايپليڪيشن SwiftUI، TabbedView، SegmentedControl، NavigationView، Form، Modal، وغيره جا بنيادي حصا استعمال ڪري ٿي. اهو پڻ مهيا ڪري ٿو ڪسٽم ڏيک، اشارو، UI/UX.

SwiftUI تي ايپليڪيشن ڊولپمينٽ. حصو 1: ڊيٽا فلو ۽ ريڊڪس
حقيقت ۾، حرکت پذير آهي، GIF ٿورڙي جرڪي ٿي وئي

ايپ تي ڪم ڪرڻ مون کي تمام گهڻو تجربو ڏنو ۽ مجموعي طور تي اهو هڪ مثبت تجربو هو. مان هڪ مڪمل فنڪشنل ايپليڪيشن لکڻ جي قابل ٿيس، سيپٽمبر ۾ آئون ان کي بهتر ڪندس ۽ ايپ اسٽور ۾ شايع ڪندس، انهي سان گڏ iOS 13 جي رليز سان.

Redux، BindableObject ۽ EnvironmentObject

SwiftUI تي ايپليڪيشن ڊولپمينٽ. حصو 1: ڊيٽا فلو ۽ ريڊڪس

مان هاڻي تقريباً ٻن سالن کان ريڊڪس سان ڪم ڪري رهيو آهيان، تنهن ڪري مان ان ۾ نسبتاً چڱيءَ طرح واقف آهيان. خاص طور تي، مان ان کي فرنٽ اينڊ ۾ استعمال ڪريان ٿو تصديق ڪريو ويب سائيٽ، انهي سان گڏ مقامي 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
}

گھٽائڻ وارو عمل ڪيو ويندو آھي جڏھن توھان ھڪڙو عمل موڪليندا آھيو ۽ ھڪڙي نئين رياست واپس ڪندا آھيو، جيئن مٿي بيان ڪيو ويو آھي.

مان اڃا تفصيل ۾ نه ويندس - ڪيئن SwiftUI اصل ۾ ڄاڻي ٿو ته ڇا ڏيکاري. انهي کي وڌيڪ تفصيل سان سمجهڻ لاء، اهو قابل آهي ڊيٽا جي وهڪري تي WWDC سيشن ڏسو SwiftUI ۾. اهو پڻ تفصيل سان بيان ڪري ٿو ته ڇو ۽ ڪڏهن استعمال ڪيو وڃي رياست, @Binding, ObjectBinding and EnvironmentObject.

Skillbox سفارش ڪري ٿو:

جو ذريعو: www.habr.com

تبصرو شامل ڪريو