Environment 中的 Core Data Context
在使用 Core Data 時會看到這樣的代碼:
@Environment(\.managedObjectContext) var managedObjectContext
在 Previews 視圖代碼中還要這樣寫:
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
return ContentView().environment(\.managedObjectContext, context)
追溯源頭,會發現在 SceneDelegate.swift
中有最早的使用:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Get the managed object context from the shared persistent container.
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
// Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath.
// Add `@Environment(\.managedObjectContext)` in the views that will need the context.
let contentView = ContentView().environment(\.managedObjectContext, context)
// Use a UIHostingController as window root view controlle
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
由代碼可知,context 在一開始就被創建,然后以 .environment(\.managedObjectContext, context)
的方式存放在 Environment 之中,供其他 View 共享。
那么 @Environment 究竟是什么呢?
顧名思義,@Environment 就是 View 所在環境的各種環境變量信息的集合。你可以通過鍵路徑 (key path) 對其讀寫。
除了 managedObjectContext 用於 Core Data 的 context 外,很多 UI 的設計都可以利用到 Environment 的各種鍵值。
用例:Environment.colorScheme
根據 Light 和 Dark 兩種系統顏色模式來調整 app 界面的配色是很常見的需求。方法很簡單,通過 Environment.colorScheme 獲取當前系統環境的顏色方案就行了:
struct ContentView: View {
// colorScheme values: .light, .dark
@Enviroment(\.colorScheme) var colorScheme
var body: some View {
Text("Hello, World")
.foregroundColor(colorScheme = .light ? .yellow : .blue)
}
}
查閱 EnvironmentValues 文檔可以獲得更多鍵值的用法。
自定義 Environment 的 Key
Environment 如此方便好用,不能自定義鍵值為我所用豈不可惜?
用稍微復雜點的對象來舉例。首先定義一個結構體:
struct Setting {
var username: String = ""
var isSoundOn: Bool = false
init(name: String) {
self.username = name
}
}
接下來我們要把它變成 Environment 的一個鍵 (EnvironmentKey):
struct SettingKey: EnvironmentKey {
static var defaultValue: Setting {
return Setting(name: "User")
}
}
這樣用到這個 key 就可以獲取它的默認值。
然后我們要擴寫 EnvironmentValues,把 Setting 加進去:
extension EnvironmentValues {
var customSetting: Setting {
get { return self[SettingKey.self] }
set { self[SettingKey] = newValue }
}
}
就這樣,customSetting 變成了 Environment 的 key,我們可以通過聲明 @Environment(\.customSetting) var customSetting: Setting
來獲取它的值,通過在 View 中 .environment(\.customSetting, Setting(name: "..."))
來修改它。
參考
本文參考了以下文章和視頻: