Hoʻomohala noi ma SwiftUI. Mahele 1: Dataflow a me Redux

Hoʻomohala noi ma SwiftUI. Mahele 1: Dataflow a me Redux

Ma hope o ka hele ʻana i ka hui State of the Union ma WWDC 2019, ua hoʻoholo wau e lawe i kahi luʻu hohonu i SwiftUI. Ua hoʻohana au i ka manawa nui me ia a ua hoʻomaka wau e hoʻomohala i kahi noi maoli e hiki ke hoʻohana i nā mea hoʻohana ākea.

Ua kapa au iā ia ʻo MovieSwiftUI - he polokalamu kēia no ka ʻimi ʻana i nā kiʻiʻoniʻoni hou a me nā kiʻiʻoniʻoni kahiko, a me ka hōʻiliʻili ʻana iā lākou i kahi hōʻiliʻili hoʻohana. API TMDB. Ua makemake mau au i nā kiʻiʻoniʻoni a ua hoʻokumu i kahi ʻoihana e hana ana ma kēia kahua, ʻoiai he wā lōʻihi ma mua. ʻAʻole hiki ke kapa ʻia ka hui ʻoluʻolu, akā ʻo ka noi!

Hoʻomaopopo mākou iā ʻoe: no ka poʻe heluhelu a pau o "Habr" - kahi ho'ēmi o 10 rubles i ka wā e kākau inoa ai i kekahi papa Skillbox e hoʻohana ana i ka code promotional "Habr".

Manaʻo ʻo Skillbox: Papa hoʻonaʻauao pūnaewele "Ka mea hoʻomohala ʻoihana Java".

No laila he aha ka MovieSwiftUI e hana ai?

  • Hoʻopili me ka API - kokoke i nā noi hou e hana i kēia.
  • Hoʻouka i ka ʻikepili asynchronous ma nā noi a hoʻopau iā JSON i ka hoʻohālike Swift me ka hoʻohana ʻana Codable.
  • Hōʻike i nā kiʻi i hoʻouka ʻia ma ke noi a hūnā iā lākou.
  • Hāʻawi kēia polokalamu no iOS, iPadOS, a me macOS i ka UX maikaʻi loa no nā mea hoʻohana o kēia mau OS.
  • Hiki i ka mea hoʻohana ke hana i ka ʻikepili a hana i kā lākou papa inoa kiʻiʻoniʻoni ponoʻī. Mālama ka polokalamu a hoʻihoʻi i ka ʻikepili mea hoʻohana.
  • Hoʻokaʻawale ʻia nā hiʻohiʻona, nā ʻāpana a me nā hiʻohiʻona me ka hoʻohana ʻana i ke ʻano Redux. ʻO ke kahe ʻikepili ma ʻaneʻi he unidirectional. Hiki ke hoʻopaʻa ʻia, hoʻihoʻi ʻia a kākau ʻia.
  • Hoʻohana ka noi i nā ʻāpana kumu o SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal, etc. Hāʻawi pū ia i nā hiʻohiʻona maʻamau, nā hana, UI / UX.

Hoʻomohala noi ma SwiftUI. Mahele 1: Dataflow a me Redux
ʻO kaʻoiaʻiʻo, ua maʻalahi ka animation, ua hoʻololi iki ka GIF

ʻO ka hana ʻana ma ka app ua hāʻawi mai iaʻu i ka ʻike he nui a ʻo ka holoʻokoʻa he ʻike maikaʻi. Ua hiki iaʻu ke kākau i kahi noi hana holoʻokoʻa, i ka mahina ʻo Kepakemapa e hoʻomaikaʻi wau a hoʻolaha iā ia ma ka AppStore, i ka manawa like me ka hoʻokuʻu ʻana o iOS 13.

Redux, BindableObject a me EnvironmentObject

Hoʻomohala noi ma SwiftUI. Mahele 1: Dataflow a me Redux

Ua hana au me Redux no ʻelua mau makahiki i kēia manawa, no laila ua ʻike maikaʻi wau i ia mea. Ma keʻano kūikawā, hoʻohana wau ia ma ka frontend no pane koke pūnaewele, a me ka hoʻomohala ʻana i nā polokalamu iOS (Swift) a me Android (Kotlin).

ʻAʻole loa au i mihi i ke koho ʻana iā Redux ma ke ʻano he hoʻolālā kahe data no ke kūkulu ʻana i kahi noi SwiftUI. ʻO nā ʻāpana paʻakikī loa i ka hoʻohana ʻana iā Redux i kahi noi UIKit e hana pū ana me ka hale kūʻai a loaʻa a kiʻi hou i ka ʻikepili a hoʻopaʻa ʻia i kāu mau manaʻo / ʻāpana. No ka hana ʻana i kēia, pono wau e hana i kahi ʻano waihona o nā mea hoʻohui (me ka hoʻohana ʻana iā ReSwift a me ReKotlin). Hana maikaʻi, akā nui ka code. ʻO ka mea pōʻino, ʻaʻole ia (a) i wehe i ke kumu.

Nuhou maikaʻi! ʻO nā mea wale nō e hopohopo ai me SwiftUI - inā ʻoe e hoʻolālā e hoʻohana iā Redux - nā hale kūʻai, mokuʻāina, a me nā mea hoʻemi. Mālama ʻia ka pilina me ka hale kūʻai e SwiftUI mahalo iā @EnvironmentObject. No laila, hoʻomaka ka hale kūʻai me kahi BindableObject.

Ua hana au i kahi pōkole Swift maʻalahi, SwiftUIFlux, e hāʻawi ana i ka hoʻohana maʻamau o Redux. I koʻu hihia he ʻāpana ia o MovieSwiftUI. ʻo wau kekahi ua kākau i kahi aʻo ʻanuʻu, e kōkua iā ʻoe e hoʻohana i kēia ʻāpana.

Pehea ia hana?

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)
    }
}

I kēlā me kēia manawa ke hoʻomaka ʻoe i kahi hana, hoʻāla ʻoe i ka pahu pahu. E loiloi ia i nā hana e like me ke kūlana o kēia manawa o ka noi. E hoʻihoʻi ia i kahi mokuʻāina hou i hoʻololi ʻia e like me ke ʻano hana a me ka ʻikepili.

ʻAe, no ka mea he BindableObject ka hale kūʻai, e hoʻomaopopo ʻo ia iā SwiftUI i ka wā e loli ai kona waiwai me ka hoʻohana ʻana i ka waiwai willChange i hāʻawi ʻia e PassthroughSubject. ʻO kēia no ka mea pono e hāʻawi ka BindableObject i kahi PublisherType, akā ʻo ka hoʻokō protocol ke kuleana no ka mālama ʻana. Ma keʻano holoʻokoʻa, he mea hana ikaika loa kēia mai Apple. No laila, i ke kaʻina hana e hiki mai ana, e kōkua ʻo SwiftUI i ke kino o nā manaʻo e like me ka loli mokuʻāina.

ʻOiaʻiʻo, ʻo kēia ka puʻuwai a me ke kilokilo o SwiftUI. I kēia manawa, i kēlā me kēia manaʻo e kau inoa i kahi mokuʻāina, e hāʻawi ʻia ka ʻike e like me ka ʻikepili i loaʻa mai ka mokuʻāina a me nā mea i loli.

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())
    }
}

Hoʻokomo ʻia ka hale kūʻai ma ke ʻano he EnvironmentObject i ka wā e hoʻomaka ai ka noi a laila hiki ke ʻike ʻia i kekahi ʻike me ka hoʻohana ʻana @EnvironmentObject. ʻAʻohe hoʻopaʻi hoʻokō no ka mea e kiʻi koke ʻia nā waiwai i loaʻa a helu ʻia mai ke kūlana noi.

Hoʻololi ke code ma luna i ke kiʻi inā hoʻololi ka pepa kiʻiʻoniʻoni.

A ua hana maoli ʻia kēia me ka laina hoʻokahi, me ke kōkua o nā manaʻo e pili ana i ka mokuʻāina. Inā ʻoe i hana pū me ReSwift ma iOS a i ʻole hoʻohui me React, e hoʻomaopopo ʻoe i ke kilokilo o SwiftUI.

I kēia manawa hiki iā ʻoe ke hoʻāʻo e hoʻāla i ka hana a hoʻolaha i ka mokuʻāina hou. Eia kekahi laʻana paʻakikī.

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!]))
            }
        }
    }
}

Ma ke code ma luna, ke hoʻohana nei au i ka hana .onDelete mai SwiftUI no kēlā me kēia IP. ʻAe kēia i ka lālani i ka papa inoa e hōʻike i ka swipe maʻamau o iOS e holoi. No laila ke hoʻopā ka mea hoʻohana i ka pihi holoi, hoʻomaka ia i ka hana kūpono a wehe i ke kiʻiʻoniʻoni mai ka papa inoa.

Ma muli o ka loaʻa ʻana o ka waiwai papa inoa mai ka mokuʻāina ʻo BindableObject a ua hoʻokomo ʻia ma ke ʻano he EnvironmentObject, ua hōʻano hou ʻo SwiftUI i ka papa inoa no ka mea pili ʻo ForEach me nā kiʻiʻoniʻoni i helu ʻia.

Eia kahi ʻāpana o ka MoviesState reducer:

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
}

Hoʻokō ʻia ka mea hoʻemi ke hoʻouna ʻoe i kahi hana a hoʻihoʻi i kahi mokuʻāina hou, e like me ka ʻōlelo ma luna.

ʻAʻole wau e hele i nā kikoʻī - pehea e ʻike maoli ai ʻo SwiftUI i ka mea e hōʻike ai. No ka hoʻomaopopo hohonu ʻana i kēia, pono ia e nānā i ke kau WWDC ma ke kahe ʻikepili ma SwiftUI. E wehewehe ana i ke kumu a me ka wā e hoʻohana ai Moku'āina, @Binding, ObjectBinding a me EnvironmentObject.

Manaʻo ʻo Skillbox:

Source: www.habr.com

Pākuʻi i ka manaʻo hoʻopuka