ืืืืจ ืฉืืฉืชืชืคืชื ืืืืฉื ืืฆื ืืืืืื ื-WWDC 2019, ืืืืืชื ืืฆืืื ืขืืืง ืืชืื SwiftUI. ืืืืืชื ืืจืื ืืื ืืขืืืื ืขื ืื ืืขืืฉืื ืืชืืืชื ืืคืชื ืืคืืืงืฆืื ืืืืชืืช ืฉืืืืื ืืืืืช ืฉืืืืฉืืช ืืืืืื ืจืื ืฉื ืืฉืชืืฉืื.
ืงืจืืชื ืืื MovieSwiftUI - ืื ืืคืืืงืฆืื ืืืืคืืฉ ืกืจืืื ืืืฉืื ืืืฉื ืื, ืืื ืื ืืืกืืฃ ืฉืืื ืืืืกืฃ ืืืืฆืขืืช
ืื ื ืืืืืจืื: ืืื ืงืืจืื Habr - ืื ืื ืฉื 10 ืจืืื ืืขืช ืืจืฉืื ืืื ืงืืจืก Skillbox ืืืืฆืขืืช ืงืื ืืืืื ืฉื Habr.
Skillbox ืืืืืฆื: ืงืืจืก ืืื ืืื ืืงืืื
"ืืงืฆืืขื ืืคืชื ื'ืืืื" .
ืื ืื MovieSwiftUI ืืืื ืืขืฉืืช?
- ืืื ืืจืืงืฆืื ืขื ื-API - ืืืขื ืื ืืคืืืงืฆืื ืืืืจื ืืช ืขืืฉื ืืืช.
- ืืืขื ื ืชืื ืื ืืกืื ืืจืื ืืื ืขื ืืงืฉืืช ืืื ืชื JSON ืืืืื Swift ืืืืฆืขืืช
ื ืืชื ืช ืืงืืืื . - ืืฆืื ืชืืื ืืช ืฉื ืืขื ื ืืคื ืืงืฉื ืืฉืืืจ ืืืชื ืืืืืื.
- ืืคืืืงืฆืื ืื ืขืืืจ iOS, iPadOS ื- macOS ืืกืคืงืช ืืช ื-UX ืืืื ืืืืชืจ ืขืืืจ ืืฉืชืืฉื ืืขืจืืืช ืืคืขืื ืืื.
- ืืืฉืชืืฉ ืืืื ืืืคืืง ื ืชืื ืื ืืืืฆืืจ ืจืฉืืืืช ืกืจืืื ืืฉืื. ืืืคืืืงืฆืื ืฉืืืจืช ืืืฉืืืจืช ื ืชืื ื ืืฉืชืืฉ.
- ืชืฆืืืืช, ืจืืืืื ืืืืืื ืืืคืจืืื ืืืืจืืจ ืืืืฆืขืืช ืืคืืก Redux. ืืจืืืช ืื ืชืื ืื ืืื ืืื ืื ืืืืื ืืช. ื ืืชื ืืืืกื ืืืชื ืืืืืื ืืืืืื, ืืฉืืืจ ืืืชื ืืืืจืืก ืืืชื.
- ืืืคืืืงืฆืื ืืฉืชืืฉืช ืืจืืืืื ืืืกืืกืืื ืฉื SwiftUI, TabbedView, SegmentedControl, NavigationView, Form, Modal ืืื'. ืื ืื ืืกืคืง ืชืฆืืืืช ืืืชืืืืช ืืืฉืืช, ืืืืืช, ืืืฉืง ืืฉืชืืฉ/UX.
ืืืขืฉื, ืืื ืืืฆืื ืืืงื, ื-GIF ืืฆื ืงืฆืช ืืืืจืฃ
ืืขืืืื ืขื ืืืคืืืงืฆืื ื ืชื ื ืื ื ืืกืืื ืจื ืืืกื ืืื ืื ืืืืชื ืืืืื ืืืืืืช. ืืฆืืืชื ืืืชืื ืืคืืืงืฆืื ืคืื ืงืฆืืื ืืืช ืืืื, ืืกืคืืืืจ ืืฉืคืจ ืืืชื ืืืคืจืกื ืืืชื ื-AppStore, ืืืงืืื ืืฉืืจืืจ iOS 13.
Redux, BindableObject ื- EnvironmentObject
ืื ื ืขืืื ืขื Redux ืืืจ ืืฉื ืชืืื, ืื ืื ื ืืงืื ืืื ืืืกืืช. ืืคืจื, ืื ื ืืฉืชืืฉ ืื ื-frontend ืขืืืจ
ืืขืืื ืื ืืฆืืขืจืชื ืฉืืืจืชื ื- Redux ืืืจืืืืงืืืจืช ืืจืืืช ืื ืชืื ืื ืืื ืืืช ืืืฉืื SwiftUI. ืืืืงืื ืืืืชืืจืื ืืืืชืจ ืืขืช ืฉืืืืฉ ื- Redux ืืืคืืืงืฆืืืช UIKit ืื ืขืืืื ืขื ืืื ืืช ืืงืืืช ืืืืืืจ ื ืชืื ืื ืืืืคืื ืืืชื ืืชืฆืืืืช/ืจืืืืื ืฉืื. ืืฉื ืื, ื ืืืฆืชื ืืืฆืืจ ืืขืื ืกืคืจืืื ืฉื ืืืืจืื (ืืืืฆืขืืช ReSwift ื-ReKotlin). ืขืืื ืืื, ืืื ืื ืืจืื ืงืื. ืืืจืื ืืฆืขืจ, ืื ืื (ืขืืืื) ืงืื ืคืชืื.
ืืืฉืืช ืืืืืช! ืืืืจืื ืืืืืืื ืฉืฆืจืื ืืืืื ืืืืืื ืขื SwiftUI - ืื ืืชื ืืชืื ื ืืืฉืชืืฉ ื- Redux - ืื ืื ืืืืช, ืืืื ืืช ืืืคืืืชืื. ืืืื ืืจืืงืฆืื ืขื ืืื ืืช ืืืืคืืช ืืืืืืื ืขื ืืื SwiftUI ืืืืืช ื-@EnvironmentObject. ืื, ืืื ืืช ืืชืืืื ืขื BindableObject.
ืืฆืจืชื ืืืืืช Swift ืคืฉืืื,
ืืื ืื ืขืืื?
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, ืื ืืืฉืื ืืคืจืืืืงืื ืืืจืื ืื ืืืืื. ืืกื ืืื, ืืื ืืื ืืืง ืืืื ืฉื ืืคื. ืืืชืื ืืื, ืืืืืืจ ืืจืื ืืืจ ืืื, 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 ืื ืืคืืื
ืืขืช ืชืืื ืื ืกืืช ืืืคืขืื ืืช ืืคืขืืื ืืืคืจืกื ืืช ืืืฆื ืืืืฉ. ืื ื ืืืืื ืืืจืืืช ืืืชืจ.
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 ืืขืฆื ืืืืข ืื ืืืฆืื. ืืื ืืืืื ืืช ืื ืืืชืจ ืืขืืืง, ืื ืฉืืื
Skillbox ืืืืืฆื:
- ืงืืจืก ืืขืฉื
"Mobile Developer PRO" .- ืงืืจืก ืืงืืื ืืืฉืืื
"Python Data Analyst" .- ืงืืจืก ืืขืฉื ืฉื ืชืืื
"ืื ื ืืคืชื ืืชืจืื PRO" .
ืืงืืจ: www.habr.com