SwiftUI මත යෙදුම් සංවර්ධනය. 1 කොටස: Dataflow සහ Redux

SwiftUI මත යෙදුම් සංවර්ධනය. 1 කොටස: Dataflow සහ Redux

WWDC 2019 හි ස්ටේට් ඔෆ් ද යූනියන් සැසියට සහභාගී වීමෙන් පසුව, මම SwiftUI වෙත ගැඹුරට කිමිදීමට තීරණය කළෙමි. මම එය සමඟ වැඩ කිරීමට බොහෝ කාලයක් ගත කර ඇති අතර දැන් පුළුල් පරාසයක පරිශීලකයින්ට ප්‍රයෝජනවත් විය හැකි සැබෑ යෙදුමක් සංවර්ධනය කිරීමට පටන් ගෙන ඇත.

මම එය හැඳින්වූයේ MovieSwiftUI ලෙසිනි - මෙය නව සහ පැරණි චිත්‍රපට සෙවීමට මෙන්ම ඒවා භාවිතයෙන් එකතුවකට එකතු කිරීමට යෙදුමකි. TMDB API. මම හැම විටම චිත්‍රපටවලට ආදරය කර ඇති අතර බොහෝ කලකට පෙර වුවද මෙම ක්ෂේත්‍රයේ වැඩ කරන සමාගමක් පවා නිර්මාණය කළෙමි. සමාගම සිසිල් ලෙස හැඳින්විය නොහැක, නමුත් යෙදුම විය!

අපි ඔබට මතක් කරමු: "Habr" හි සියලුම පාඨකයින් සඳහා - "Habr" ප්‍රවර්ධන කේතය භාවිතයෙන් ඕනෑම Skillbox පාඨමාලාවකට ලියාපදිංචි වන විට රූබල් 10 ක වට්ටමක්.

Skillbox නිර්දේශ කරයි: අධ්‍යාපනික මාර්ගගත පාඨමාලාව "වෘත්තීය ජාවා සංවර්ධක".

ඉතින් MovieSwiftUI හට කුමක් කළ හැකිද?

  • API සමඟ අන්තර්ක්‍රියා කරයි - ඕනෑම නවීන යෙදුමක් පාහේ මෙය කරයි.
  • ඉල්ලීම් මත අසමමුහුර්ත දත්ත පූරණය කරන අතර භාවිතා කරන Swift ආකෘතියට JSON විග්‍රහ කරයි කේතනය කළ හැකි.
  • ඉල්ලීම මත පටවා ඇති පින්තූර පෙන්වමින් ඒවා හැඹිලි කරයි.
  • iOS, iPadOS සහ macOS සඳහා වන මෙම යෙදුම මෙම OS භාවිතා කරන්නන් සඳහා හොඳම UX සපයයි.
  • පරිශීලකයාට දත්ත උත්පාදනය කර ඔවුන්ගේම චිත්‍රපට ලැයිස්තු සෑදිය හැක. යෙදුම පරිශීලක දත්ත සුරැකීම සහ ප්රතිෂ්ඨාපනය කරයි.
  • Redux රටාව භාවිතයෙන් දර්ශන, සංරචක සහ ආකෘති පැහැදිලිව වෙන් කර ඇත. මෙහි දත්ත ප්‍රවාහය ඒක දිශානුගත වේ. එය සම්පූර්ණයෙන්ම හැඹිලිගත කළ හැක, ප්රතිෂ්ඨාපනය කර නැවත ලිවිය හැක.
  • යෙදුම SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal යනාදී මූලික සංරචක භාවිතා කරයි. එය අභිරුචි දසුන්, අභිනයන්, UI/UX ද සපයයි.

SwiftUI මත යෙදුම් සංවර්ධනය. 1 කොටස: Dataflow සහ Redux
ඇත්ත වශයෙන්ම, සජීවිකරණය සිනිඳුයි, GIF ටිකක් අවුල් සහගත විය

යෙදුම මත වැඩ කිරීම මට බොහෝ අත්දැකීම් ලබා දුන් අතර සමස්තයක් ලෙස එය ධනාත්මක අත්දැකීමක් විය. මට සම්පුර්ණයෙන්ම ක්‍රියාකාරී යෙදුමක් ලිවීමට හැකි විය, සැප්තැම්බර් මාසයේදී මම එය වැඩිදියුණු කර iOS 13 නිකුතුවට සමගාමීව AppStore හි ප්‍රකාශයට පත් කරමි.

Redux, BindableObject සහ EnvironmentObject

SwiftUI මත යෙදුම් සංවර්ධනය. 1 කොටස: Dataflow සහ Redux

මම දැන් අවුරුදු දෙකක් විතර Redux එක්ක වැඩ කරනවා, ඒ නිසා මම ඒ ගැන සාපේක්ෂ වශයෙන් හොඳින් දන්නවා. විශේෂයෙන්, මම එය ඉදිරිපස කොටසෙහි භාවිතා කරමි React වෙබ් අඩවිය, මෙන්ම දේශීය iOS (Swift) සහ Android (Kotlin) යෙදුම් සංවර්ධනය කිරීම සඳහා.

SwiftUI යෙදුමක් තැනීම සඳහා දත්ත ප්‍රවාහ ගෘහ නිර්මාණ ශිල්පය ලෙස Redux තෝරා ගැනීම ගැන මම කිසිවිටක පසුතැවිලි වී නැත. UIKit යෙදුමක Redux භාවිතා කරන විට වඩාත්ම අභියෝගාත්මක කොටස් වන්නේ ගබඩාව සමඟ වැඩ කිරීම සහ දත්ත ලබා ගැනීම සහ ලබා ගැනීම සහ එය ඔබගේ බැලීම්/සංරචක වෙත සිතියම්ගත කිරීමයි. මෙය සිදු කිරීම සඳහා, මට සම්බන්ධක පුස්තකාලයක් (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 එකක් වන බැවින්, PassthroughSubject විසින් සපයන ලද willChange දේපල භාවිතයෙන් එහි අගය වෙනස් වන විට එය SwiftUI වෙත දැනුම් දෙනු ඇත. මක්නිසාද යත් 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 භාවිතයෙන් ඕනෑම දර්ශනයකින් ප්‍රවේශ විය හැක. ව්‍යුත්පන්න ගුණාංග ඉක්මනින් ලබා ගැනීම හෝ යෙදුම් තත්ත්වයෙන් ගණනය කිරීම නිසා කාර්ය සාධන දඩයක් නොමැත.

චිත්‍රපට පෝස්ටරය වෙනස් වුවහොත් ඉහත කේතය රූපය වෙනස් කරයි.

මෙය ඇත්ත වශයෙන්ම සිදු කරනු ලබන්නේ එක් පේළියකින් පමණක් වන අතර, දර්ශන රාජ්‍යයට සම්බන්ධ කර ඇති ආධාරයෙන්. ඔබ 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 ලෙස එන්නත් කර ඇති බැවින්, ForEach චිත්‍රපට ගණනය කළ දේපල සමඟ සම්බන්ධ වී ඇති නිසා SwiftUI ලැයිස්තුව යාවත්කාලීන කරයි.

මෙන්න 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

අදහස් එක් කරන්න