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

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

WWDC 2019 рдЪреНрдпрд╛ рд╕реНрдЯреЗрдЯ рдСрдл рдж рдпреБрдирд┐рдпрди рд╕рддреНрд░рд╛рдд рд╕рд╣рднрд╛рдЧреА рдЭрд╛рд▓реНрдпрд╛рдирдВрддрд░, рдореА SwiftUI рдордзреНрдпреЗ рдЦреЛрд▓рд╡рд░ рдЬрд╛рдгреНрдпрд╛рдЪрд╛ рдирд┐рд░реНрдгрдп рдШреЗрддрд▓рд╛. рдореА рддреНрдпрд╛рдЪреНрдпрд╛рд╕реЛрдмрдд рдХрд╛рдо рдХрд░рдгреНрдпрд╛рдд рдмрд░рд╛рдЪ рд╡реЗрд│ рдШрд╛рд▓рд╡рд▓рд╛ рдЖрд╣реЗ рдЖрдгрд┐ рдЖрддрд╛ рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдгреНрдпрд╛рд╕ рд╕реБрд░реБрд╡рд╛рдд рдХреЗрд▓реА рдЖрд╣реЗ рдЬреА рд╡рд╛рдкрд░рдХрд░реНрддреНрдпрд╛рдВрдЪреНрдпрд╛ рд╡рд┐рд╕реНрддреГрдд рд╢реНрд░реЗрдгреАрд╕рд╛рдареА рдЙрдкрдпреБрдХреНрдд рдЕрд╕реВ рд╢рдХрддреЗ.

рдореА рдпрд╛рд▓рд╛ MovieSwiftUI рдореНрд╣рдЯрд▓реЗ - рд╣реЗ рдирд╡реАрди рдЖрдгрд┐ рдЬреБрдиреЗ рдЪрд┐рддреНрд░рдкрдЯ рд╢реЛрдзрдгреНрдпрд╛рд╕рд╛рдареА рддрд╕реЗрдЪ рд╕рдВрдЧреНрд░рд╣рд╛рдд рд╕рдВрдЧреНрд░рд╣рд┐рдд рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдПрдХ рдЕреЕрдк рдЖрд╣реЗ TMDB API. рдорд▓рд╛ рдиреЗрд╣рдореАрдЪ рдЪрд┐рддреНрд░рдкрдЯрд╛рдВрдЪреА рдЖрд╡рдб рдЖрд╣реЗ рдЖрдгрд┐ рдпрд╛ рдХреНрд╖реЗрддреНрд░рд╛рдд рдХрд╛рдо рдХрд░рдгрд╛рд░реА рдПрдХ рдХрдВрдкрдиреА рджреЗрдЦреАрд▓ рдореА рдЦреВрдк рдкреВрд░реНрд╡реАрдкрд╛рд╕реВрди рддрдпрд╛рд░ рдХреЗрд▓реА рдЖрд╣реЗ. рдХрдВрдкрдиреАрд▓рд╛ рдХреНрд╡рдЪрд┐рддрдЪ рдорд╕реНрдд рдореНрд╣рдгрддрд╛ рдпреЗрдИрд▓, рдкрдг рдЕрд░реНрдЬ рд╣реЛрддрд╛!

рдЖрдореНрд╣реА рдЖрдард╡рдг рдХрд░реВрди рджреЗрддреЛ: рд╕рд░реНрд╡ Habr рд╡рд╛рдЪрдХрд╛рдВрд╕рд╛рдареА - Habr рдкреНрд░реЛрдореЛ рдХреЛрдб рд╡рд╛рдкрд░реВрди рдХреЛрдгрддреНрдпрд╛рд╣реА рд╕реНрдХрд┐рд▓рдмреЙрдХреНрд╕ рдХреЛрд░реНрд╕рдордзреНрдпреЗ рдирд╛рд╡рдиреЛрдВрджрдгреА рдХрд░рддрд╛рдирд╛ 10 рд░реВрдмрд▓ рд╕рд╡рд▓рдд.

рд╕реНрдХрд┐рд▓рдмреЙрдХреНрд╕ рд╢рд┐рдлрд╛рд░рд╕ рдХрд░рддреЛ: рд╢реИрдХреНрд╖рдгрд┐рдХ рдСрдирд▓рд╛рдЗрди рдЕрднреНрдпрд╛рд╕рдХреНрд░рдо "рдкреНрд░реЛрдлреЗрд╢рди рдЬрд╛рд╡рд╛ рдбреЗрд╡реНрд╣рд▓рдкрд░".

рддрд░ MovieSwiftUI рдХрд╛рдп рдХрд░реВ рд╢рдХрддреЗ?

  • API рд╕рд╣ рд╕рдВрд╡рд╛рдж рд╕рд╛рдзрддреЛ - рдЬрд╡рд│рдЬрд╡рд│ рдХреЛрдгрддрд╛рд╣реА рдЖрдзреБрдирд┐рдХ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╣реЗ рдХрд░рддреЛ.
  • рд╡рд┐рдирдВрддреНрдпрд╛рдВрд╡рд░ рдЕрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдбреЗрдЯрд╛ рд▓реЛрдб рдХрд░рддреЗ рдЖрдгрд┐ JSON рд╡рд╛рдкрд░реВрди рд╕реНрд╡рд┐рдлреНрдЯ рдореЙрдбреЗрд▓рдордзреНрдпреЗ рдкрд╛рд░реНрд╕ рдХрд░рддреЗ рдХреЛрдбреЗрдмрд▓.
  • рд╡рд┐рдирдВрддреАрдиреБрд╕рд╛рд░ рд▓реЛрдб рдХреЗрд▓реЗрд▓реНрдпрд╛ рдкреНрд░рддрд┐рдорд╛ рджрд░реНрд╢рд╡рд┐рддреЗ рдЖрдгрд┐ рддреНрдпрд╛рдВрдирд╛ рдХреЕрд╢ рдХрд░рддреЗ.
  • iOS, iPadOS рдЖрдгрд┐ macOS рд╕рд╛рдареА рд╣реЗ рдЕреЕрдк рдпрд╛ OS рдЪреНрдпрд╛ рд╡рд╛рдкрд░рдХрд░реНрддреНрдпрд╛рдВрд╕рд╛рдареА рд╕рд░реНрд╡реЛрддреНрддрдо UX рдкреНрд░рджрд╛рди рдХрд░рддреЗ.
  • рд╡рд╛рдкрд░рдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рд╡реНрдпреБрддреНрдкрдиреНрди рдХрд░реВ рд╢рдХрддреЛ рдЖрдгрд┐ рддреНрдпрд╛рдВрдЪреНрдпрд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ рдЪрд┐рддреНрд░рдкрдЯрд╛рдВрдЪреНрдпрд╛ рд╕реВрдЪреА рддрдпрд╛рд░ рдХрд░реВ рд╢рдХрддреЛ. рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд╛рдкрд░рдХрд░реНрддреНрдпрд╛рдЪрд╛ рдбреЗрдЯрд╛ рд╡рд╛рдЪрд╡рддреЛ рдЖрдгрд┐ рдкреБрдирд░реНрд╕рдВрдЪрдпрд┐рдд рдХрд░рддреЛ.
  • Redux рдкреЕрдЯрд░реНрди рд╡рд╛рдкрд░реВрди рджреГрд╢реНрдпреЗ, рдШрдЯрдХ рдЖрдгрд┐ рдореЙрдбреЗрд▓ рд╕реНрдкрд╖реНрдЯрдкрдгреЗ рд╡реЗрдЧрд│реЗ рдХреЗрд▓реЗ рдЬрд╛рддрд╛рдд. рдпреЗрдереЗ рдбреЗрдЯрд╛ рдкреНрд░рд╡рд╛рд╣ рджрд┐рд╢рд╛рд╣реАрди рдЖрд╣реЗ. рд╣реЗ рдкреВрд░реНрдгрдкрдгреЗ рдХреЕрд╢реЗ, рдкреБрдирд░реНрд╕рдВрдЪрдпрд┐рдд рдЖрдгрд┐ рдЕрдзрд┐рд▓рд┐рдЦрд┐рдд рдХреЗрд▓реЗ рдЬрд╛рдК рд╢рдХрддреЗ.
  • рдЕреЕрдкреНрд▓рд┐рдХреЗрд╢рди рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдп, рдЯреЕрдмрдбрд╡реНрд╣реНрдпреВ, рд╕реЗрдЧрдореЗрдВрдЯреЗрдб рдХрдВрдЯреНрд░реЛрд▓, рдиреЗрд╡реНрд╣рд┐рдЧреЗрд╢рди рд╡реНрд╣реНрдпреВ, рдлреЙрд░реНрдо, рдореЙрдбреЗрд▓ рдЗ.рдЪреЗ рдореВрд▓рднреВрдд рдШрдЯрдХ рд╡рд╛рдкрд░рддреЗ. рд╣реЗ рд╕рд╛рдиреБрдХреВрд▓ рджреГрд╢реНрдпреЗ, рдЬреЗрд╢реНрдЪрд░, UI/UX рджреЗрдЦреАрд▓ рдкреНрд░рджрд╛рди рдХрд░рддреЗ.

SwiftUI рд╡рд░ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд┐рдХрд╛рд╕. рднрд╛рдЧ рез: рдбреЗрдЯрд╛рдлреНрд▓реЛ рдЖрдгрд┐ рд░реЗрдбрдХреНрд╕
рдЦрд░рдВ рддрд░, рдЕреЕрдирд┐рдореЗрд╢рди рдЧреБрд│рдЧреБрд│реАрдд рдЖрд╣реЗ, рдЬреАрдЖрдпрдПрдл рдереЛрдбрд╛ рдзрдХреНрдХрд╛рджрд╛рдпрдХ рдЖрд╣реЗ

рдЕреЕрдкрд╡рд░ рдХрд╛рдо рдХреЗрд▓реНрдпрд╛рдиреЗ рдорд▓рд╛ рдЦреВрдк рдЕрдиреБрднрд╡ рдорд┐рд│рд╛рд▓рд╛ рдЖрдгрд┐ рдПрдХреВрдгрдЪ рд╣рд╛ рдПрдХ рд╕рдХрд╛рд░рд╛рддреНрдордХ рдЕрдиреБрднрд╡ рд╣реЛрддрд╛. рдореА рдкреВрд░реНрдгрдкрдгреЗ рдХрд╛рд░реНрдпрд╢реАрд▓ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд▓рд┐рд╣реВ рд╢рдХрд▓реЛ, рд╕рдкреНрдЯреЗрдВрдмрд░рдордзреНрдпреЗ рдореА рддреНрдпрд╛рдд рд╕реБрдзрд╛рд░рдгрд╛ рдХрд░реЗрди рдЖрдгрд┐ рддреНрдпрд╛рдЪ рд╡реЗрд│реА iOS 13 рдЪреНрдпрд╛ рд░рд┐рд▓реАрдЭрд╕рд╣ рдЕреЕрдкрд╕реНрдЯреЛрд░рдордзреНрдпреЗ рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░реЗрди.

Redux, BindableObject рдЖрдгрд┐ EnvironmentObject

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

рдореА рдЖрддрд╛ рд╕реБрдорд╛рд░реЗ рджреЛрди рд╡рд░реНрд╖рд╛рдВрдкрд╛рд╕реВрди Redux рд╕рд╣ рдХрд╛рдо рдХрд░рдд рдЖрд╣реЗ, рдореНрд╣рдгреВрди рдореА рддреНрдпрд╛рдд рддреБрд▓рдиреЗрдиреЗ рдкрд╛рд░рдВрдЧрдд рдЖрд╣реЗ. рд╡рд┐рд╢реЗрд╖рддрдГ, рдореА рддреЗ рдлреНрд░рдВрдЯрдПрдВрдбрдордзреНрдпреЗ рд╡рд╛рдкрд░рддреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рджреНрдпрд╛ рд╡реЗрдмрд╕рд╛рдЗрдЯ, рддрд╕реЗрдЪ рдореВрд│ iOS (Swift) рдЖрдгрд┐ Android (Kotlin) рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА.

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

рдЪрд╛рдВрдЧрд▓реА рдмрд╛рддрдореА! SwiftUI рд╕рд╣ рдХрд╛рд│рдЬреА рдХрд░рдгреНрдпрд╛рд╕рд╛рд░рдЦреНрдпрд╛ рдЧреЛрд╖реНрдЯреА - рдЬрд░ рддреБрдореНрд╣реА 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 рдкреНрд░рджрд╛рди рдХрд░рдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ, рдкрд░рдВрддреБ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдЕрдВрдорд▓рдмрдЬрд╛рд╡рдгреА рд╣реЗ рд╡реНрдпрд╡рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдЬрдмрд╛рдмрджрд╛рд░ рдЖрд╣реЗ. рдПрдХреВрдгрдЪ, рд╣реЗ рдНрдкрд▓рдЪреЗ рдПрдХ рдЕрддрд┐рд╢рдп рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рд╕рд╛рдзрди рдЖрд╣реЗ. рддреНрдпрд╛рдиреБрд╕рд╛рд░, рдкреБрдвреАрд▓ рд░реЗрдВрдбрд░рд┐рдВрдЧ рд╕рд╛рдпрдХрд▓рдордзреНрдпреЗ, рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдп рд░рд╛рдЬреНрдп рдмрджрд▓рд╛рдиреБрд╕рд╛рд░ рджреГрд╢реНрдпрд╛рдВрдЪреЗ рдореБрдЦреНрдп рднрд╛рдЧ рдкреНрд░рд╕реНрддреБрдд рдХрд░рдгреНрдпрд╛рдд рдорджрдд рдХрд░реЗрд▓.

рд╡рд╛рд╕реНрддрд╡рд┐рдХ, рд╣реЗ рд╕рд░реНрд╡ рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдпрдЪреЗ рд╣реГрджрдп рдЖрдгрд┐ рдЬрд╛рджреВ рдЖрд╣реЗ. рдЖрддрд╛, рд░рд╛рдЬреНрдпрд╛рдЪреЗ рд╕рджрд╕реНрдпрддреНрд╡ рдШреЗрддрд▓реЗрд▓реНрдпрд╛ рдХреЛрдгрддреНрдпрд╛рд╣реА рджреГрд╢реНрдпрд╛рдд, рд░рд╛рдЬреНрдпрд╛рдХрдбреВрди рдХреЛрдгрддрд╛ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдЭрд╛рд▓рд╛ рдЖрдгрд┐ рдХрд╛рдп рдмрджрд▓рд▓реЗ рдЖрд╣реЗ рддреНрдпрд╛рдиреБрд╕рд╛рд░ рджреГрд╢реНрдп рдкреНрд░рд╕реНрддреБрдд рдХреЗрд▓реЗ рдЬрд╛рдИрд▓.

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
}

рдЬреЗрд╡реНрд╣рд╛ рддреБрдореНрд╣реА рдПрдЦрд╛рджреА рдХреНрд░рд┐рдпрд╛ рдкрд╛рдард╡рддрд╛ рдЖрдгрд┐ рд╡рд░ рд╕рд╛рдВрдЧрд┐рддрд▓реНрдпрд╛рдкреНрд░рдорд╛рдгреЗ рдирд╡реАрди рд╕реНрдерд┐рддреА рдкрд░рдд рдХрд░рддрд╛ рддреЗрд╡реНрд╣рд╛ рд░реЗрдбреНрдпреВрд╕рд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХреЗрд▓рд╛ рдЬрд╛рддреЛ.

рдореА рдЕрдЬреВрди рддрдкрд╢реАрд▓рд╛рдд рдЬрд╛рдгрд╛рд░ рдирд╛рд╣реА - рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдпрд▓рд╛ рдкреНрд░рддреНрдпрдХреНрд╖рд╛рдд рдХрд╛рдп рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рд╛рдпрдЪреЗ рд╣реЗ рдХрд╕реЗ рдорд╛рд╣рд┐рдд рдЖрд╣реЗ. рд╣реЗ рдЕрдзрд┐рдХ рд╕рдЦреЛрд▓рдкрдгреЗ рд╕рдордЬреВрди рдШреЗрдгреНрдпрд╛рд╕рд╛рдареА, рддреЗ рдлрд╛рдпрджреЗрд╢реАрд░ рдЖрд╣реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╡рд╛рд╣рд╛рд╡рд░ WWDC рд╕рддреНрд░ рдкрд╣рд╛ SwiftUI рдордзреНрдпреЗ. рддреЗ рдХрд╛ рдЖрдгрд┐ рдХреЗрд╡реНрд╣рд╛ рд╡рд╛рдкрд░рд╛рдпрдЪреЗ рд╣реЗ рджреЗрдЦреАрд▓ рддрдкрд╢реАрд▓рд╡рд╛рд░ рд╕реНрдкрд╖реНрдЯ рдХрд░рддреЗ рд░рд╛рдЬреНрдп, @Binding, ObjectBinding рдЖрдгрд┐ EnvironmentObject.

рд╕реНрдХрд┐рд▓рдмреЙрдХреНрд╕ рд╢рд┐рдлрд╛рд░рд╕ рдХрд░рддреЛ:

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

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╛