@EnvironmentObject
1. Giới thiệu
Phần tiêu đề “1. Giới thiệu”@EnvironmentObject chia sẻ data xuyên suốt View hierarchy.
class AppSettings: ObservableObject { @Published var isDarkMode = false @Published var language = "en"}
@mainstruct MyApp: App { @StateObject var settings = AppSettings()
var body: some Scene { WindowGroup { ContentView() .environmentObject(settings) } }}2. Inject và Access
Phần tiêu đề “2. Inject và Access”Inject tại root
Phần tiêu đề “Inject tại root”ContentView() .environmentObject(settings)Access trong child views
Phần tiêu đề “Access trong child views”struct ChildView: View { @EnvironmentObject var settings: AppSettings
var body: some View { Text("Dark mode: \(settings.isDarkMode ? "On" : "Off")") }}3. Ví dụ: Theme Manager
Phần tiêu đề “3. Ví dụ: Theme Manager”class ThemeManager: ObservableObject { @Published var isDarkMode = false @Published var accentColor = Color.blue
var backgroundColor: Color { isDarkMode ? .black : .white }
var textColor: Color { isDarkMode ? .white : .black }}
struct RootView: View { @StateObject var themeManager = ThemeManager()
var body: some View { TabView { HomeView() SettingsView() } .environmentObject(themeManager) .preferredColorScheme(themeManager.isDarkMode ? .dark : .light) }}
struct HomeView: View { @EnvironmentObject var theme: ThemeManager
var body: some View { VStack { Text("Home") .foregroundColor(theme.textColor) } .background(theme.backgroundColor) }}
struct SettingsView: View { @EnvironmentObject var theme: ThemeManager
var body: some View { Form { Toggle("Dark Mode", isOn: $theme.isDarkMode)
ColorPicker("Accent Color", selection: $theme.accentColor) } }}4. User Session
Phần tiêu đề “4. User Session”class UserSession: ObservableObject { @Published var currentUser: User? @Published var isAuthenticated = false
func login(email: String, password: String) async throws { // API call currentUser = User(name: "John", email: email) isAuthenticated = true }
func logout() { currentUser = nil isAuthenticated = false }}
struct AppRootView: View { @StateObject var session = UserSession()
var body: some View { Group { if session.isAuthenticated { MainTabView() } else { LoginView() } } .environmentObject(session) }}
struct ProfileView: View { @EnvironmentObject var session: UserSession
var body: some View { VStack { if let user = session.currentUser { Text("Welcome, \(user.name)") }
Button("Logout") { session.logout() } } }}5. Shopping Cart
Phần tiêu đề “5. Shopping Cart”class CartManager: ObservableObject { @Published var items: [CartItem] = []
var total: Double { items.reduce(0) { $0 + $1.price * Double($1.quantity) } }
var itemCount: Int { items.reduce(0) { $0 + $1.quantity } }
func add(_ product: Product) { if let index = items.firstIndex(where: { $0.productId == product.id }) { items[index].quantity += 1 } else { items.append(CartItem(productId: product.id, name: product.name, price: product.price, quantity: 1)) } }
func remove(_ item: CartItem) { items.removeAll { $0.id == item.id } }}
struct ProductCard: View { let product: Product @EnvironmentObject var cart: CartManager
var body: some View { VStack { Text(product.name) Text("$\(product.price, specifier: "%.2f")")
Button("Add to Cart") { cart.add(product) } .buttonStyle(.borderedProminent) } }}
struct CartBadge: View { @EnvironmentObject var cart: CartManager
var body: some View { ZStack(alignment: .topTrailing) { Image(systemName: "cart")
if cart.itemCount > 0 { Text("\(cart.itemCount)") .font(.caption2) .foregroundColor(.white) .padding(4) .background(Circle().fill(.red)) .offset(x: 8, y: -8) } } }}6. Multiple EnvironmentObjects
Phần tiêu đề “6. Multiple EnvironmentObjects”struct App: App { @StateObject var userSession = UserSession() @StateObject var settings = AppSettings() @StateObject var cart = CartManager()
var body: some Scene { WindowGroup { ContentView() .environmentObject(userSession) .environmentObject(settings) .environmentObject(cart) } }}7. Preview với EnvironmentObject
Phần tiêu đề “7. Preview với EnvironmentObject”#Preview { ProductCard(product: Product(name: "iPhone", price: 999)) .environmentObject(CartManager())}8. So sánh
Phần tiêu đề “8. So sánh”| Feature | @StateObject | @EnvironmentObject |
|---|---|---|
| Tạo object | ✅ | ❌ |
| Pass qua init | ❌ | ❌ |
| Inject | - | .environmentObject() |
| Scope | View đó | Toàn bộ subtree |
📝 Tóm tắt
Phần tiêu đề “📝 Tóm tắt”- Inject với
.environmentObject(object) - Access với
@EnvironmentObject var obj: Type - Dùng cho global state: theme, user session, cart
- Phải inject trước khi access (crash nếu không có)
- Dùng chung reference, thay đổi affect tất cả views