SwiftUI жүйесінде қолданбаларды әзірлеу. 1-бөлім: Dataflow және Redux

SwiftUI жүйесінде қолданбаларды әзірлеу. 1-бөлім: Dataflow және Redux

WWDC 2019-дағы Одақтың жағдайы сессиясына қатысқаннан кейін мен SwiftUI-ге терең бойлауды шештім. Мен онымен жұмыс істеуге көп уақыт жұмсадым және енді пайдаланушылардың кең ауқымына пайдалы болатын нақты қолданбаны әзірлеуге кірістім.

Мен оны MovieSwiftUI деп атадым - бұл жаңа және ескі фильмдерді іздеуге, сондай-ақ оларды пайдалану арқылы коллекцияға жинауға арналған қолданба. TMDB API. Мен фильмдерді әрқашан жақсы көремін және тіпті осы салада жұмыс істейтін компанияны құрдым, бірақ көп уақыт бұрын. Компанияны керемет деп атауға болмайды, бірақ қолданба болды!

Біз еске саламыз: «Хабрдың» барлық оқырмандары үшін - «Habr» жарнамалық кодын пайдаланып кез келген Skillbox курсына жазылу кезінде 10 000 рубль көлемінде жеңілдік.

Skillbox ұсынады: Білім беру онлайн курсы «Мамандығы Java әзірлеушісі».

Сонымен, MovieSwiftUI не істей алады?

  • API интерфейсімен әрекеттеседі - кез келген дерлік заманауи қолданба мұны жасайды.
  • Сұраулар бойынша асинхронды деректерді жүктейді және пайдалану арқылы Swift үлгісіне JSON талдайды Кодталатын.
  • Сұраныс бойынша жүктелген кескіндерді көрсетеді және оларды кэштейді.
  • iOS, iPadOS және macOS жүйесіне арналған бұл қолданба осы ОЖ пайдаланушылары үшін ең жақсы UX ұсынады.
  • Пайдаланушы деректерді генерациялай алады және өзінің фильм тізімдерін жасай алады. Қолданба пайдаланушы деректерін сақтайды және қалпына келтіреді.
  • Көріністер, құрамдас бөліктер және үлгілер Redux үлгісі арқылы анық бөлінген. Мұндағы деректер ағыны бір бағытты. Оны толық кэштеуге, қалпына келтіруге және қайта жазуға болады.
  • Қолданба SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal және т.б. негізгі құрамдастарын пайдаланады. Ол сондай-ақ реттелетін көріністерді, қимылдарды, UI/UX ұсынады.

SwiftUI жүйесінде қолданбаларды әзірлеу. 1-бөлім: Dataflow және Redux
Шын мәнінде, анимация тегіс, GIF сәл дірілдеп шықты

Қолданбада жұмыс істеу маған көп тәжірибе берді және тұтастай алғанда бұл оң тәжірибе болды. Мен толық жұмыс істейтін қосымшаны жаза алдым, қыркүйекте мен оны жетілдіремін және iOS 13 шығарылымымен бір уақытта AppStore-да жариялаймын.

Redux, BindableObject және EnvironmentObject

SwiftUI жүйесінде қолданбаларды әзірлеу. 1-бөлім: Dataflow және Redux

Мен Redux-пен екі жылдай жұмыс істеп жатырмын, сондықтан мен оны салыстырмалы түрде жақсы білемін. Атап айтқанда, мен оны frontend үшін қолданамын жауап веб-сайт, сонымен қатар жергілікті iOS (Swift) және Android (Kotlin) қосымшаларын әзірлеуге арналған.

SwiftUI қолданбасын құру үшін деректер ағынының архитектурасы ретінде Redux таңдағаныма ешқашан өкінген емеспін. Redux қолданбасын UIKit қолданбасында пайдалану кезінде ең қиын бөліктер дүкенмен жұмыс істеу және деректерді алу және шығарып алу және оны көріністерге/компоненттерге салыстыру болып табылады. Мұны істеу үшін маған қосқыштар кітапханасының түрін жасау керек болды (ReSwift және ReKotlin көмегімен). Жақсы жұмыс істейді, бірақ өте көп код. Өкінішке орай, бұл (әлі) ашық бастапқы код емес.

Жақсы жаңалықтар! SwiftUI-мен алаңдауға болатын жалғыз нәрсе - егер сіз Redux пайдалануды жоспарласаңыз - дүкендер, штаттар және редукторлар. Дүкенмен өзара әрекеттесу @EnvironmentObject арқасында толығымен SwiftUI арқылы қамтамасыз етіледі. Сонымен, дүкен BindableObject нысанынан басталады.

Мен қарапайым Swift пакетін жасадым, 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 болғандықтан, PassthroughSubject ұсынған willChange сипатын пайдаланып мәні өзгерген кезде ол SwiftUI туралы хабарлайды. Себебі, BindableObject PublisherType түрін қамтамасыз етуі керек, бірақ протоколды іске асыру оны басқаруға жауапты. Жалпы, бұл Apple компаниясының өте қуатты құралы. Тиісінше, келесі көрсету циклінде 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!]))
            }
        }
    }
}

Жоғарыдағы кодта мен әр IP үшін SwiftUI қолданбасынан .onDelete әрекетін қолданамын. Бұл тізімдегі жолға жою үшін қалыпты iOS сипауын көрсетуге мүмкіндік береді. Сонымен, пайдаланушы жою түймесін басқан кезде, ол сәйкес әрекетті іске қосады және фильмді тізімнен жояды.

Тізім сипаты BindableObject күйінен алынған және EnvironmentObject ретінде енгізілгендіктен, SwiftUI тізімді жаңартады, себебі ForEach фильмдердің есептелген сипатымен байланысты.

Мұнда 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
}

Редуктор жоғарыда айтылғандай әрекетті жіберіп, жаңа күйді қайтарған кезде орындалады.

Мен әлі егжей-тегжейлі айтпаймын - SwiftUI нені көрсету керектігін қалай біледі. Мұны тереңірек түсіну үшін бұл тұр деректер ағынында WWDC сеансын көру SwiftUI ішінде. Ол сондай-ақ не үшін және қашан пайдалану керектігін егжей-тегжейлі түсіндіреді мемлекет, @Binding, ObjectBinding және EnvironmentObject.

Skillbox ұсынады:

Ақпарат көзі: www.habr.com

пікір қалдыру