تطيل البنية المتوازنة لتطبيقات الهاتف المحمول من عمر المشروع والمطورين.
التاريخ
قابل أليكس. يحتاج إلى تطوير تطبيق لعمل قائمة تسوق. أليكس هو مطور متمرس وأولًا أشكال متطلبات المنتج:
- القدرة على نقل المنتج إلى منصات أخرى (watchOS و macOS و tvOS)
- الانحدار الآلي الكامل للتطبيق
- دعم IOS 13+
تعرف أليكس مؤخرًا على مشروع pointfree.com ، حيث شارك براندون وستيفن رؤيتهما في هندسة التطبيقات الحديثة. هذه هي الطريقة التي اكتشف بها أليكس حول Composable Architecutre.
بنية قابلة للتركيب
بعد مراجعة وثائق Composable Architecture ، قرر أليكس أنه كان يتعامل مع بنية أحادية الاتجاه تتوافق مع متطلبات التصميم. من الكتيب الذي يتبعه:
- تقسيم المشروع إلى وحدات ؛
- واجهة مستخدم تعتمد على البيانات - يتم تحديد تكوين الواجهة حسب حالتها ؛
- يتم تغطية كل منطق الوحدة من خلال اختبارات الوحدة ؛
- اختبار اللقطات للواجهات ؛
- يدعم iOS 13+ و macOS و tvOS و watchOS ؛
- دعم SwiftUI و UIKit.
قبل الغوص في دراسة الهندسة المعمارية ، دعنا نلقي نظرة على شيء مثل المظلة الذكية.
كيف تصف النظام الذي يتم ترتيب المظلة به؟
يتكون نظام المظلة من أربعة مكونات:
. : .
. .
. .
. 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)
الجزء 3 - توسيع الوظائف وإضافة إزالة المنتج والفرز (قيد التقدم)
الجزء 4 - أضف قائمة التخزين المؤقت وانتقل إلى المتجر (قيد التقدم)
المصادر
قائمة المنتجات الجزء 1: github.com
بوابة مؤلفي النهج: pointfree.com
مصادر العمارة القابلة للتركيب: https://github.com/pointfreeco/swift-composable-architecture