Arsitektur yang seimbang dari aplikasi seluler memperpanjang umur proyek dan pengembang.
Sejarah
Temui Alex. Ia perlu mengembangkan aplikasi untuk membuat daftar belanjaan. Alex adalah pengembang berpengalaman dan pertama-tama persyaratan untuk produk:
- Kemampuan untuk mem-port produk ke platform lain (watchOS, macOS, tvOS)
- Regresi aplikasi yang sepenuhnya otomatis
- Dukungan IOS 13+
Alex baru-baru ini berkenalan dengan proyek pointfree.com , di mana Brandon dan Stephen berbagi wawasan mereka tentang arsitektur aplikasi modern. Inilah cara Alex mengetahui tentang Composable Architecutre.
Arsitektur yang Dapat Disusun
Setelah meninjau dokumentasi Arsitektur Kompos, Alex memutuskan bahwa dia berurusan dengan arsitektur searah yang sesuai dengan persyaratan desain. Dari brosur itu diikuti:
- Membagi proyek menjadi modul;
- UI berbasis data - konfigurasi antarmuka ditentukan oleh statusnya;
- Semua logika modul dicakup oleh pengujian unit;
- Pengujian snapshot antarmuka;
- Mendukung iOS 13+, macOS, tvOS dan watchOS;
- Dukungan SwiftUI dan UIKit.
Sebelum terjun ke studi arsitektur, mari kita lihat objek seperti payung pintar.
Bagaimana cara mendeskripsikan sistem pengaturan payung?
Sistem payung memiliki empat komponen:
. : .
. .
. .
. 10 .
composable architecture . .
? , .
UI β [];
Action β ;
State β [];
Environment β [ ];
Reducer β , [] ;
Effect β , action reducer.
( 1)
.
. , .
struct ShoppingListState {
var products: [Product] = []
}
enum ShoppingListAction {
case addProduct
}
reducer :
let shoppingListReducer = Reducer { state, action, env in
switch action {
case .addProduct:
state.products.insert(Product(), at: 0)
return .none
}
}
:
struct Product {
var id = UUID()
var name = ""
var isInBox = false
}
enum ProductAction {
case toggleStatus
case updateName(String)
}
let productReducer = Reducer { state, action, env in
switch action {
case .toggleStatus:
state.isInBox.toggle()
return .none
case .updateName(let newName):
state.name = newName
return .none
}
}
, reducer , , . reducer .
UI .
UI
iOS 13+ Composable Architecture SwiftUI, .
, Store:
typealias ShoppingListStore = Store<ShoppingListState, ShoppingListAction>
let store = ShoppingListStore(
initialState: ShoppingListState(products: []),
reducer: shoppingListReducer,
environment: ShoppingListEnviroment()
)
Store viewModel MVVM β .
let view = ShoppingListView(store: store)
struct ShoppingListView: View {
let store: ShoppingListStore
var body: some View {
Text("Hello, World!")
}
}
Composable Architecture SwiftUI. , store ObservedObject, WithViewStore:
var body: some View {
WithViewStore(store) { viewStore in
NavigationView {
Text("\(viewStore.products.count)")
.navigationTitle("Shopping list")
.navigationBarItems(
trailing: Button("Add item") {
viewStore.send(.addProduct)
}
)
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
Add item, . send(Action) .
, , :
struct ProductView: View {
let store: ProductStore
var body: some View {
WithViewStore(store) { viewStore in
HStack {
Button(action: { viewStore.send(.toggleStatus) }) {
Image(
systemName: viewStore.isInBox
? "checkmark.square"
: "square"
)
}
.buttonStyle(PlainButtonStyle())
TextField(
"New item",
text: viewStore.binding(
get: \.name,
send: ProductAction.updateName
)
)
}
.foregroundColor(viewStore.isInBox ? .gray : nil)
}
}
}
. ? .
enum ShoppingListAction {
//
case productAction(Int, ProductAction)
case addProduct
}
//
// .. ,
let shoppingListReducer: Reducer<ShoppingListState, ShoppingListAction, ShoppingListEnviroment> = .combine(
// ,
productReducer.forEach(
// Key path
state: ShoppingListState.products,
// Case path
action: /ShoppingListAction.productAction,
environment: { _ in ProductEnviroment() }
),
Reducer { state, action, env in
switch action {
case .addProduct:
state.products.insert(Product(), at: 0)
return .none
// productReducer
case .productAction:
return .none
}
}
)
. .
UI :
var body: some View {
WithViewStore(store) { viewStore in
NavigationView {
List {
//
ForEachStore(
// store
store.scope(
state: \.products,
action: ShoppingListAction.productAction
),
//
content: ProductView.init
)
}
.navigationTitle("Shopping list")
.navigationBarItems(
trailing: Button("Add item") {
viewStore.send(.addProduct)
}
)
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
150 , .
2 β (in progress)
Bagian 3 - memperluas fungsionalitas, menambahkan penghapusan dan penyortiran produk (dalam proses)
Bagian 4 - tambahkan cache daftar dan pergi ke toko (dalam proses)
Sumber
Daftar Produk Bagian 1: github.com
Portal penulis pendekatan: pointfree.com
Sumber Arsitektur Komposabel: https://github.com/pointfreeco/swift-composable-architecture