SwiftUI 中 @Environment 的用法
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: "...")) 来修改它。
参考
本文参考了以下文章和视频:
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号