Таҳияи барномаҳо дар SwiftUI. Қисми 1: Dataflow ва Redux

Таҳияи барномаҳо дар SwiftUI. Қисми 1: Dataflow ва Redux

Пас аз иштирок дар ҷаласаи Вазъияти Иттиҳод дар WWDC 2019, ман қарор додам, ки ба SwiftUI ғарқ шавам. Ман вақти зиёдро бо он сарф кардам ва ҳоло ба таҳияи як барномаи воқеӣ шурӯъ кардам, ки метавонад барои доираи васеи корбарон муфид бошад.

Ман онро MovieSwiftUI номидам - ​​ин барнома барои ҷустуҷӯи филмҳои нав ва кӯҳна, инчунин ҷамъоварии онҳо дар маҷмӯа бо истифода аз API TMDB. Ман ҳамеша филмҳоро дӯст медоштам ва ҳатто як ширкате таъсис додам, ки дар ин соҳа кор мекунад, ҳарчанд хеле пеш. Ширкатро базӯр хуб номидан мумкин нест, аммо барнома буд!

Мо ба шумо хотиррасон мекунем: барои ҳамаи хонандагони "Habr" - тахфифи 10 000 рубл ҳангоми номнавис шудан ба курсҳои Skillbox бо истифода аз рамзи таблиғотии "Habr".

Skillbox тавсия медиҳад: Курси онлайни таълимӣ "Касби Java Developer".

Пас MovieSwiftUI чӣ кор карда метавонад?

  • Бо API ҳамкорӣ мекунад - қариб ҳама замимаҳои муосир ин корро мекунанд.
  • Бо истифода аз дархостҳо маълумоти асинхронӣ бор мекунад ва JSON-ро ба модели Swift таҳлил мекунад Рамзшаванда.
  • Тасвирҳои бо дархост боршударо нишон медиҳад ва онҳоро кэш мекунад.
  • Ин барнома барои iOS, iPadOS ва macOS беҳтарин UX-ро барои корбарони ин ОС таъмин мекунад.
  • Истифодабаранда метавонад маълумот тавлид кунад ва рӯйхати филмҳои худро эҷод кунад. Барнома маълумоти корбарро захира ва барқарор мекунад.
  • Намоишҳо, ҷузъҳо ва моделҳо бо истифода аз намунаи Redux ба таври возеҳ ҷудо карда мешаванд. Ҷараёни маълумот дар ин ҷо якҷониба аст. Он метавонад пурра кэш карда шавад, барқарор карда шавад ва аз нав навишта шавад.
  • Барнома ҷузъҳои асосии SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal ва ғайраҳоро истифода мебарад. Он инчунин назари фармоишӣ, имову ишораҳо, UI/UX-ро таъмин мекунад.

Таҳияи барномаҳо дар SwiftUI. Қисми 1: Dataflow ва Redux
Дарвоқеъ, аниматсия ҳамвор аст, GIF каме ғафс баромад

Кор дар барнома ба ман таҷрибаи зиёд дод ва дар маҷмӯъ ин як таҷрибаи мусбат буд. Ман тавонистам як барномаи комилан функсионалӣ нависам, дар моҳи сентябр ман онро такмил медиҳам ва онро дар AppStore ҳамзамон бо нашри iOS 13 нашр мекунам.

Redux, BindableObject ва EnvironmentObject

Таҳияи барномаҳо дар SwiftUI. Қисми 1: Dataflow ва Redux

Ман тақрибан ду сол боз бо Redux кор мекунам, бинобар ин ман онро нисбатан хуб медонам. Махсусан, ман онро дар фронт барои Натиҷа вебсайт, инчунин барои таҳияи барномаҳои аслии iOS (Swift) ва Android (Kotlin).

Ман ҳеҷ гоҳ пушаймон нашудаам, ки Redux-ро ҳамчун меъмории ҷараёни маълумот барои сохтани барномаи SwiftUI интихоб кардам. Қисмҳои душвортарин ҳангоми истифодаи 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 аст, он SwiftUI-ро ҳангоми тағир додани арзиши он бо истифода аз хосияти willChange аз ҷониби PassthroughSubject огоҳ мекунад. Сабаб дар он аст, ки 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 дастрас мешавад. Ягон ҷаримаи иҷроиш вуҷуд надорад, зеро хосиятҳои ҳосилшуда аз ҳолати барнома зуд гирифта мешаванд ё ҳисоб карда мешаванд.

Рамзи боло тасвирро тағир медиҳад, агар плакати филм тағир ёбад.

Ва ин дар асл бо як сатр сурат мегирад, ки бо ёрии он дидгоҳҳо ба давлат пайваст мешаванд. Агар шумо бо ReSwift дар iOS кор карда бошед ё ҳатто пайваст кардан бо 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 бо амволи ҳисобшудаи филмҳо алоқаманд аст.

Ин аст як қисми редуктори 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 тавсия медиҳад:

Манбаъ: will.com

Илова Эзоҳ