Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π½Π° прилоТСния Π½Π° SwiftUI. Част 1: Dataflow ΠΈ Redux

Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π½Π° прилоТСния Π½Π° SwiftUI. Част 1: Dataflow ΠΈ Redux

Π‘Π»Π΅Π΄ ΠΊΠ°Ρ‚ΠΎ ΠΏΡ€ΠΈΡΡŠΡΡ‚Π²Π°Ρ… Π½Π° сСсията Π·Π° ΡΡŠΡΡ‚ΠΎΡΠ½ΠΈΠ΅Ρ‚ΠΎ Π½Π° Бъюза Π½Π° WWDC 2019, Ρ€Π΅ΡˆΠΈΡ… Π΄Π° сС потопя дълбоко Π² SwiftUI. ΠŸΡ€Π΅ΠΊΠ°Ρ€Π°Ρ… ΠΌΠ½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅ Π² Ρ€Π°Π±ΠΎΡ‚Π° с Π½Π΅Π³ΠΎ ΠΈ сСга Π·Π°ΠΏΠΎΡ‡Π½Π°Ρ… Π΄Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π²Π°ΠΌ истинско ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΊΠΎΠ΅Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС ΠΏΠΎΠ»Π΅Π·Π½ΠΎ Π·Π° ΡˆΠΈΡ€ΠΎΠΊ ΠΊΡ€ΡŠΠ³ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΈΡ‚Π΅Π»ΠΈ.

НарСкох Π³ΠΎ MovieSwiftUI - Ρ‚ΠΎΠ²Π° Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π·Π° Ρ‚ΡŠΡ€ΡΠ΅Π½Π΅ Π½Π° Π½ΠΎΠ²ΠΈ ΠΈ стари Ρ„ΠΈΠ»ΠΌΠΈ, ΠΊΠ°ΠΊΡ‚ΠΎ ΠΈ ΡΡŠΠ±ΠΈΡ€Π°Π½Π΅Ρ‚ΠΎ ΠΈΠΌ Π² колСкция с TMDB API. Π’ΠΈΠ½Π°Π³ΠΈ съм ΠΎΠ±ΠΈΡ‡Π°Π» Ρ„ΠΈΠ»ΠΌΠΈΡ‚Π΅ ΠΈ Π΄ΠΎΡ€ΠΈ ΡΡŠΠ·Π΄Π°Π΄ΠΎΡ… компания, Ρ€Π°Π±ΠΎΡ‚Π΅Ρ‰Π° Π² Ρ‚Π°Π·ΠΈ област, ΠΌΠ°ΠΊΠ°Ρ€ ΠΈ ΠΌΠ½ΠΎΠ³ΠΎ ΠΎΡ‚Π΄Π°Π²Π½Π°. ΠšΠΎΠΌΠΏΠ°Π½ΠΈΡΡ‚Π° Ρ‚Ρ€ΡƒΠ΄Π½ΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° сС Π½Π°Ρ€Π΅Ρ‡Π΅ Π³ΠΎΡ‚ΠΈΠ½Π°, Π½ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ бСшС!

НапомнямС Π²ΠΈ: Π·Π° всички Ρ‡ΠΈΡ‚Π°Ρ‚Π΅Π»ΠΈ Π½Π° "Habr" - ΠΎΡ‚ΡΡ‚ΡŠΠΏΠΊΠ° ΠΎΡ‚ 10 000 Ρ€ΡƒΠ±Π»ΠΈ ΠΏΡ€ΠΈ записванС във всСки курс Skillbox, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΠΊΠΈ промоционалния ΠΊΠΎΠ΄ Π½Π° "Habr".

Skillbox ΠΏΡ€Π΅ΠΏΠΎΡ€ΡŠΡ‡Π²Π°: ΠžΠ±Ρ€Π°Π·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅Π½ ΠΎΠ½Π»Π°ΠΉΠ½ курс β€žΠŸΡ€ΠΎΡ„Π΅ΡΠΈΡ Java Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊβ€œ.

И Ρ‚Π°ΠΊΠ°, ΠΊΠ°ΠΊΠ²ΠΎ ΠΌΠΎΠΆΠ΅ Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈ 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 - са ΠΌΠ°Π³Π°Π·ΠΈΠ½ΠΈ, ΡΡŠΡΡ‚ΠΎΡΠ½ΠΈΡ ΠΈ Ρ€Π΅Π΄ΡƒΠΊΡ‚ΠΎΡ€ΠΈ. ВзаимодСйствиСто с ΠΌΠ°Π³Π°Π·ΠΈΠ½Π° сС ΠΏΠΎΠ΅ΠΌΠ° изцяло ΠΎΡ‚ SwiftUI Π±Π»Π°Π³ΠΎΠ΄Π°Ρ€Π΅Π½ΠΈΠ΅ Π½Π° @EnvironmentObject. И Ρ‚Π°ΠΊΠ°, ΠΌΠ°Π³Π°Π·ΠΈΠ½ΡŠΡ‚ Π·Π°ΠΏΠΎΡ‡Π²Π° с 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)
    }
}

ВсСки ΠΏΡŠΡ‚, ΠΊΠΎΠ³Π°Ρ‚ΠΎ задСйстватС дСйствиС, Π²ΠΈΠ΅ Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€Π°Ρ‚Π΅ скоростната кутия. Π’ΠΎΠΉ Ρ‰Π΅ ΠΎΡ†Π΅Π½ΠΈ дСйствията спорСд Ρ‚Π΅ΠΊΡƒΡ‰ΠΎΡ‚ΠΎ ΡΡŠΡΡ‚ΠΎΡΠ½ΠΈΠ΅ Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ. Π‘Π»Π΅Π΄ Ρ‚ΠΎΠ²Π° Ρ‰Π΅ Π²ΡŠΡ€Π½Π΅ Π½ΠΎΠ²ΠΎ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΡ†ΠΈΡ€Π°Π½ΠΎ ΡΡŠΡΡ‚ΠΎΡΠ½ΠΈΠ΅ Π² ΡΡŠΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΠΈΠ΅ с Ρ‚ΠΈΠΏΠ° Π½Π° дСйствиСто ΠΈ Π΄Π°Π½Π½ΠΈΡ‚Π΅.

Π•, Ρ‚ΡŠΠΉ ΠΊΠ°Ρ‚ΠΎ store Π΅ 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 Π·Π° ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅. Π’Π°ΠΊΠ° Ρ‡Π΅, ΠΊΠΎΠ³Π°Ρ‚ΠΎ потрСбитСлят докоснС Π±ΡƒΡ‚ΠΎΠ½Π° Π·Π° ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅, Ρ‚ΠΎΠΉ задСйства ΡΡŠΠΎΡ‚Π²Π΅Ρ‚Π½ΠΎΡ‚ΠΎ дСйствиС ΠΈ ΠΏΡ€Π΅ΠΌΠ°Ρ…Π²Π° Ρ„ΠΈΠ»ΠΌΠ° ΠΎΡ‚ списъка.

Π•, Ρ‚ΡŠΠΉ ΠΊΠ°Ρ‚ΠΎ свойството list сС ΠΈΠ·Π²Π»ΠΈΡ‡Π° ΠΎΡ‚ ΡΡŠΡΡ‚ΠΎΡΠ½ΠΈΠ΅Ρ‚ΠΎ BindableObject ΠΈ сС ΠΈΠ½ΠΆΠ΅ΠΊΡ‚ΠΈΡ€Π° ΠΊΠ°Ρ‚ΠΎ EnvironmentObject, SwiftUI Π°ΠΊΡ‚ΡƒΠ°Π»ΠΈΠ·ΠΈΡ€Π° списъка, Ρ‚ΡŠΠΉ ΠΊΠ°Ρ‚ΠΎ ForEach Π΅ ΡΠ²ΡŠΡ€Π·Π°Π½ с изчислСното свойство movies.

Π•Ρ‚ΠΎ част ΠΎΡ‚ Ρ€Π΅Π΄ΡƒΠΊΡ‚ΠΎΡ€Π° 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

ДобавянС Π½Π° Π½ΠΎΠ² ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€