SwiftUI рдорд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд┐рдХрд╛рд╕ред рднрд╛рдЧ рез: рдбрд╛рдЯрд╛рдлреНрд▓реЛ рд░ рд░реЗрдбрдХреНрд╕

SwiftUI рдорд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд┐рдХрд╛рд╕ред рднрд╛рдЧ рез: рдбрд╛рдЯрд╛рдлреНрд▓реЛ рд░ рд░реЗрдбрдХреНрд╕

WWDC 2019 рдорд╛ рд╕реНрдЯреЗрдЯ рдЕрдл рдж рдпреБрдирд┐рдпрди рд╕рддреНрд░рдорд╛ рднрд╛рдЧ рд▓рд┐рдПрдкрдЫрд┐, рдореИрд▓реЗ SwiftUI рдорд╛ рдЧрд╣рд┐рд░реЛ рдбреБрдмреНрдиреЗ рдирд┐рд░реНрдгрдп рдЧрд░реЗрдВред рдореИрд▓реЗ рдпрд╕рдХреЛ рд╕рд╛рде рдХрд╛рдо рдЧрд░реНрдиреЗ рдзреЗрд░реИ рд╕рдордп рдмрд┐рддрд╛рдПрдБ рд░ рдЕрдм рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд┐рдХрд╛рд╕ рдЧрд░реНрди рдерд╛рд▓реЗрдХреЛ рдЫреБ рдЬреБрди рдкреНрд░рдпреЛрдЧрдХрд░реНрддрд╛рд╣рд░реВрдХреЛ рд╡рд┐рд╕реНрддреГрдд рджрд╛рдпрд░рд╛рдХреЛ рд▓рд╛рдЧрд┐ рдЙрдкрдпреЛрдЧреА рд╣реБрди рд╕рдХреНрдЫред

рдореИрд▓реЗ рдпрд╕рд▓рд╛рдИ MovieSwiftUI рднрдирд┐рдиреНрдЫ - рдпреЛ рдирдпрд╛рдБ рд░ рдкреБрд░рд╛рдирд╛ рдЪрд▓рдЪрд┐рддреНрд░рд╣рд░реВ рдЦреЛрдЬреНрдирдХреЛ рд▓рд╛рдЧрд┐ рдПрдЙрдЯрд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╣реЛ, рд╕рд╛рдереИ рддрд┐рдиреАрд╣рд░реВрд▓рд╛рдИ рд╕рдЩреНрдЧреНрд░рд╣рдорд╛ рд╕рдЩреНрдХрд▓рди рдЧрд░реНрдиреЗ TMDB APIред рдореИрд▓реЗ рд╕рдзреИрдВ рдЪрд▓рдЪрд┐рддреНрд░рд╣рд░реВ рдорди рдкрд░рд╛рдПрдХреЛ рдЫреБ рд░ рдпрд╕ рдХреНрд╖реЗрддреНрд░рдорд╛ рдХрд╛рдо рдЧрд░реНрдиреЗ рдХрдореНрдкрдиреА рдкрдирд┐ рдЦреЛрд▓реЗрдХреЛ рдЫреБ, рдпрджреНрдпрдкрд┐ рдзреЗрд░реИ рд╕рдордп рдЕрдШрд┐ред рдХрдореНрдкрдиреАрд▓рд╛рдИ рдХреВрд▓ рднрдиреНрди рд╕рдХрд┐рдБрджреИрди, рддрд░ рдЖрд╡реЗрджрди рдерд┐рдпреЛ!

рд╣рд╛рдореА рд╕рдореНрдЭрд╛рдЙрдБрдЫреМрдВ: рд╕рдмреИ Habr рдкрд╛рдардХрд╣рд░реВрдХрд╛ рд▓рд╛рдЧрд┐ - Habr рдкреНрд░реЛрдореЛ рдХреЛрдб рдкреНрд░рдпреЛрдЧ рдЧрд░реА рдХреБрдиреИ рдкрдирд┐ Skillbox рдкрд╛рдареНрдпрдХреНрд░рдордорд╛ рднрд░реНрдирд╛ рдЧрд░реНрджрд╛ резреж,режрежреж рд░реВрдмрд▓ рдЫреБрдЯред

Skillbox рд╕рд┐рдлрд╛рд░рд┐рд╕ рдЧрд░реНрджрдЫ: рд╢реИрдХреНрд╖рд┐рдХ рдЕрдирд▓рд╛рдЗрди рдкрд╛рдареНрдпрдХреНрд░рдо "рдкреЗрд╢реЗ рдЬрд╛рднрд╛ рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛".

рддреНрдпрд╕реЛрднрдП MovieSwiftUI рдХреЗ рдЧрд░реНрди рд╕рдХреНрдЫ?

  • API рд╕рдБрдЧ рдЕрдиреНрддрд░реНрдХреНрд░рд┐рдпрд╛ рдЧрд░реНрджрдЫ - рд▓рдЧрднрдЧ рдХреБрдиреИ рдкрдирд┐ рдЖрдзреБрдирд┐рдХ рдЕрдиреБрдкреНрд░рдпреЛрдЧрд▓реЗ рдпреЛ рдЧрд░реНрдЫред
  • рдЕрдиреБрд░реЛрдзрд╣рд░реВрдорд╛ рдПрд╕рд┐рдиреНрдХреНрд░реЛрдирд╕ рдбреЗрдЯрд╛ рд▓реЛрдб рдЧрд░реНрджрдЫ рд░ JSON рд▓рд╛рдИ рд╕реНрд╡рд┐рдлреНрдЯ рдореЛрдбреЗрд▓ рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ рдкрд╛рд░реНрд╕ рдЧрд░реНрджрдЫ рдХреЛрдбреЗрдмрд▓.
  • рдЕрдиреБрд░реЛрдзрдорд╛ рд▓реЛрдб рдЧрд░рд┐рдПрдХрд╛ рдЫрд╡рд┐рд╣рд░реВ рджреЗрдЦрд╛рдЙрдБрджрдЫ рд░ рддрд┐рдиреАрд╣рд░реВрд▓рд╛рдИ рдХреНрдпрд╛рд╕ рдЧрд░реНрджрдЫред
  • iOS, iPadOS, рд░ macOS рдХреЛ рд▓рд╛рдЧрд┐ рдпреЛ рдПрдкрд▓реЗ рдпреА OS рдХрд╛ рдкреНрд░рдпреЛрдЧрдХрд░реНрддрд╛рд╣рд░реВрдХрд╛ рд▓рд╛рдЧрд┐ рдЙрддреНрддрдо UX рдкреНрд░рджрд╛рди рдЧрд░реНрджрдЫред
  • рдкреНрд░рдпреЛрдЧрдХрд░реНрддрд╛рд▓реЗ рдбрд╛рдЯрд╛ рдЙрддреНрдкрдиреНрди рдЧрд░реНрди рд░ рдЖрдлреНрдиреИ рдЪрд▓рдЪрд┐рддреНрд░ рд╕реВрдЪреАрд╣рд░реВ рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реНрди рд╕рдХреНрдЫред рдЕрдиреБрдкреНрд░рдпреЛрдЧрд▓реЗ рдкреНрд░рдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рдмрдЪрдд рд░ рдкреБрдирд░реНрд╕реНрдерд╛рдкрдирд╛ рдЧрд░реНрджрдЫред
  • рджреГрд╢реНрдп, рдХрдореНрдкреЛрдиреЗрдиреНрдЯ рд░ рдореЛрдбреЗрд▓рд╣рд░реВ Redux рдврд╛рдБрдЪрд╛ рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ рд╕реНрдкрд╖реНрдЯ рд░реВрдкрдорд╛ рдЫреБрдЯреНрдпрд╛рдЗрдПрдХрд╛ рдЫрдиреНред рдпрд╣рд╛рдБ рдбрд╛рдЯрд╛ рдкреНрд░рд╡рд╛рд╣ рджрд┐рд╢рд╛рд╣реАрди рдЫред рдпрд╕рд▓рд╛рдИ рдкреВрд░реНрдг рд░реВрдкрдорд╛ рдХреНрдпрд╛рд╕, рдкреБрдирд░реНрд╕реНрдерд╛рдкрдирд╛ рд░ рдЕрдзрд┐рд▓реЗрдЦрди рдЧрд░реНрди рд╕рдХрд┐рдиреНрдЫред
  • рдЕрдиреБрдкреНрд░рдпреЛрдЧрд▓реЗ SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal, рдЖрджрд┐ рдХреЛ рдЖрдзрд╛рд░рднреВрдд рдХрдореНрдкреЛрдиреЗрдиреНрдЯрд╣рд░реВ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрджрдЫред рдпрд╕рд▓реЗ рдЕрдиреБрдХреВрд▓рди рджреГрд╢реНрдпрд╣рд░реВ, рдЗрд╢рд╛рд░рд╛рд╣рд░реВ, UI/UX рдкрдирд┐ рдкреНрд░рджрд╛рди рдЧрд░реНрджрдЫред

SwiftUI рдорд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд┐рдХрд╛рд╕ред рднрд╛рдЧ рез: рдбрд╛рдЯрд╛рдлреНрд▓реЛ рд░ рд░реЗрдбрдХреНрд╕
рд╡рд╛рд╕реНрддрд╡рдорд╛, рдПрдирд┐рдореЗрд╕рди рдЪрд┐рдХрдиреА рдЫ, GIF рдЕрд▓рд┐рдХрддрд┐ рдЭрдЯрдХрд╛ рднрдпреЛ

рдПрдкрдорд╛ рдХрд╛рдо рдЧрд░реНрджрд╛ рдорд▓рд╛рдИ рдзреЗрд░реИ рдЕрдиреБрднрд╡ рджрд┐рдпреЛ рд░ рд╕рдордЧреНрд░рдорд╛ рдпреЛ рд╕рдХрд╛рд░рд╛рддреНрдордХ рдЕрдиреБрднрд╡ рдерд┐рдпреЛред рдореИрд▓реЗ рдПрдХ рдкреВрд░реНрдг рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд▓реЗрдЦреНрди рд╕рдХреНрд╖рдо рднрдПрдБ, рд╕реЗрдкреНрдЯреЗрдореНрдмрд░рдорд╛ рдо рдпрд╕рд▓рд╛рдИ рд╕реБрдзрд╛рд░ рдЧрд░реНрдиреЗрдЫреБ рд░ рдпрд╕рд▓рд╛рдИ рдПрдкрд╕реНрдЯреЛрд░рдорд╛ рдкреНрд░рдХрд╛рд╢рд┐рдд рдЧрд░реНрдиреЗрдЫреБ, рдЖрдИрдУрдПрд╕ 13 рдХреЛ рд░рд┐рд▓реАрдЬрдХреЛ рд╕рд╛рдеред

Redux, BindableObject рд░ EnvironmentObject

SwiftUI рдорд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд┐рдХрд╛рд╕ред рднрд╛рдЧ рез: рдбрд╛рдЯрд╛рдлреНрд▓реЛ рд░ рд░реЗрдбрдХреНрд╕

рдо рд░реЗрдбрдХреНрд╕рд╕рдБрдЧ рд▓рдЧрднрдЧ рджреБрдИ рд╡рд░реНрд╖рджреЗрдЦрд┐ рдХрд╛рдо рдЧрд░рд┐рд░рд╣реЗрдХреЛ рдЫреБ, рддреНрдпрд╕реИрд▓реЗ рдо рдпрд╕рдорд╛ рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рд░рд╛рдореНрд░реЛрд╕рдБрдЧ рдирд┐рдкреБрдг рдЫреБред рд╡рд┐рд╢реЗрд╖ рдЧрд░реА, рдо рдпрд╕рд▓рд╛рдИ рдлреНрд░рдиреНрдЯрдПрдиреНрдбрдорд╛ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрджрдЫреБ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╡реЗрдмрд╕рд╛рдЗрдЯ, рд╕рд╛рдереИ рдиреЗрдЯрд┐рдн рдЖрдИрдУрдПрд╕ (рд╕реНрд╡рд┐рдлреНрдЯ) рд░ рдПрдиреНрдбреНрд░реЛрдЗрдб (рдХреЛрдЯрд▓рд┐рди) рдЕрдиреБрдкреНрд░рдпреЛрдЧрд╣рд░реВ рд╡рд┐рдХрд╛рд╕ рдЧрд░реНрдирдХрд╛ рд▓рд╛рдЧрд┐ред

рдореИрд▓реЗ рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рдПрдкреНрд▓рд┐рдХреЗрд╕рди рдирд┐рд░реНрдорд╛рдг рдЧрд░реНрдирдХреЛ рд▓рд╛рдЧрд┐ рдбрд╛рдЯрд╛ рдлреНрд▓реЛ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░рдХреЛ рд░реВрдкрдорд╛ Redux рдЫрдиреМрдЯ рдЧрд░реЗрдХреЛрдорд╛ рдХрд╣рд┐рд▓реНрдпреИ рдкрдЫреБрддрд╛рдПрдХреЛ рдЫреИрдиред UIKit рдПрдкрдорд╛ Redux рдкреНрд░рдпреЛрдЧ рдЧрд░реНрджрд╛ рд╕рдмреИрднрдиреНрджрд╛ рдЪреБрдиреМрддреАрдкреВрд░реНрдг рднрд╛рдЧрд╣рд░реВ рд╕реНрдЯреЛрд░рд╕рдБрдЧ рдХрд╛рдо рдЧрд░реНрдиреЗ рд░ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрдиреЗ рд░ рдкреБрди: рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрдиреЗ рд░ рдпрд╕рд▓рд╛рдИ рддрдкрд╛рдИрдВрдХреЛ рджреГрд╢реНрдп/рдХрдореНрдкреЛрдиреЗрдиреНрдЯрд╣рд░реВрдорд╛ рдореНрдпрд╛рдк рдЧрд░реНрдиреЗ рд╣реЛред рдпреЛ рдЧрд░реНрдирдХреЛ рд▓рд╛рдЧрд┐, рдореИрд▓реЗ рдХрдиреЗрдХреНрдЯрд░рд╣рд░реВрдХреЛ рдПрдХ рдкреНрд░рдХрд╛рд░рдХреЛ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реНрдиреБрдкрд░реНтАНрдпреЛ (ReSwift рд░ ReKotlin рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░)ред рд░рд╛рдореНрд░реЛрд╕рдБрдЧ рдХрд╛рдо рдЧрд░реНрджрдЫ, рддрд░ рдзреЗрд░реИ рдХреЛрдбред рджреБрд░реНрднрд╛рдЧреНрдпрд╡рд╢, рдпреЛ (рдЕрдЭреИ) рдЦреБрд▓рд╛ рд╕реНрд░реЛрдд рд╣реЛрдЗрдиред

рдЦреБрд╕реАрдХреЛ рдЦрдмрд░! рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИрдХреЛ рд╕рд╛рде рдЪрд┐рдиреНрддрд╛ рдЧрд░реНрдиреЗ рдорд╛рддреНрд░ рдЪреАрдЬрд╣рд░реВ - рдпрджрд┐ рддрдкрд╛рдЗрдБ Redux рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдпреЛрдЬрдирд╛ рдмрдирд╛рдЙрдиреБрд╣реБрдиреНрдЫ - рд╕реНрдЯреЛрд░рд╣рд░реВ, рд░рд╛рдЬреНрдпрд╣рд░реВ, рд░ рдШрдЯрд╛рдЙрдиреЗрд╣рд░реВ рд╣реБрдиреНред рд╕реНрдЯреЛрд░рд╕рдБрдЧрдХреЛ рдЕрдиреНрддрд░рдХреНрд░рд┐рдпрд╛рд▓рд╛рдИ рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рджреНрд╡рд╛рд░рд╛ рдкреВрд░реНрдг рд░реВрдкрдорд╛ рд╣реЗрд░рдЪрд╛рд╣ рдЧрд░рд┐рдПрдХреЛ рдЫ @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 рднрдПрдХреЛрд▓реЗ, PassthroughSubject рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдЧрд░рд┐рдПрдХреЛ willChange рдЧреБрдг рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ рдпрд╕рдХреЛ рдорд╛рди рдкрд░рд┐рд╡рд░реНрддрди рд╣реБрдБрджрд╛ рдпрд╕рд▓реЗ SwiftUI рд▓рд╛рдИ рд╕реВрдЪрд┐рдд рдЧрд░реНрдиреЗрдЫред рдпреЛ рдХрд┐рдирднрдиреЗ 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 рд╕рдБрдЧ рдХрд╛рдо рдЧрд░реНрдиреБрднрдПрдХреЛ рдЫ рднрдиреЗ рдХрдиреЗрдХреНрдЯрдЖрдЗрдкреАрдПрд╕ рдПрдк рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рдХреЛ рд╕рд╛рде, рддрдкрд╛рдИрдВрд▓реЗ 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 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
}

рдорд╛рдерд┐ рдЙрд▓реНрд▓реЗрдЦ рдЧрд░рд┐рдП рдЕрдиреБрд╕рд╛рд░, рддрдкрд╛рдИрдВрд▓реЗ рдХрд╛рд░реНрдп рдкрдард╛рдЙрдБрджрд╛ рд░ рдирдпрд╛рдБ рдЕрд╡рд╕реНрдерд╛ рдлрд░реНрдХрд╛рдЙрдБрджрд╛ рд░рд┐рдбреНрдпреВрд╕рд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реБрдиреНрдЫред

рдо рдЕрдЭреИ рд╡рд┐рд╕реНрддрд╛рд░рдорд╛ рдЬрд╛рдиреЗрдЫреИрди - рдХрд╕рд░реА SwiftUI рд▓рд╛рдИ рд╡рд╛рд╕реНрддрд╡рдорд╛ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдЧрд░реНрдиреЗ рдерд╛рд╣рд╛ рдЫред рдпрд╕рд▓рд╛рдИ рдЕрдЭ рдЧрд╣рд┐рд░реЛ рд░реВрдкрдорд╛ рдмреБрдЭреНрди, рдпреЛ рд▓рд╛рдпрдХ рдЫ рдбрд╛рдЯрд╛ рдкреНрд░рд╡рд╛рд╣ рдорд╛ WWDC рд╕рддреНрд░ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН SwiftUI рдорд╛ред рдпрд╕рд▓реЗ рдХрд┐рди рд░ рдХрд╣рд┐рд▓реЗ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рднрдиреЗрд░ рдкрдирд┐ рд╡рд┐рд╕реНрддреГрдд рд░реВрдкрдорд╛ рд╡рд░реНрдгрди рдЧрд░реНрджрдЫ рд░рд╛рдЬреНрдп, @Binding, ObjectBinding рд░ EnvironmentObjectред

Skillbox рд╕рд┐рдлрд╛рд░рд┐рд╕ рдЧрд░реНрджрдЫ:

рд╕реНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдердкреНрди