@EnvironmentObject trong SwiftUI
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"
}
@main
struct MyApp: App {
@StateObject var settings = AppSettings()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(settings)
}
}
}2. Inject và Access
Inject tại root
ContentView()
.environmentObject(settings)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
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
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
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
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
#Preview {
ProductCard(product: Product(name: "iPhone", price: 999))
.environmentObject(CartManager())
}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
- 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
Last updated on