环境变量未传递给子视图
Environment variable not passed to Subviews
我想开始使用 Core Data 和 SwiftUI,因此使用最新的 Xcode 11.1 GM 创建了一个新的 watchOS 项目。
然后,我从一个新的 iOS 项目(启用了核心数据)中复制了 persistentContainer
和 saveContext
,以获得核心数据功能。
之后我将HostingController
修改为returnAnyView
并在环境中设置变量
class HostingController: WKHostingController<AnyView> {
override var body: AnyView {
let managedObjectContext = (WKExtension.shared().delegate as! ExtensionDelegate).persistentContainer.viewContext
return AnyView(ContentView().environment(\.managedObjectContext, managedObjectContext))
}
}
现在我可以访问 ContentView
、 中的上下文,但不能访问其子视图。
但这不是它的本意吗?据我所知,所有子视图都应该从其父视图继承其环境,对吗?
现在,要在其子视图中访问它,我只需再次设置环境变量,如下所示:
ContentView.swift
NavigationLink(destination: ProjectsView().environment(\.managedObjectContext, managedObjectContext)) {
HStack {
Image(systemName: "folder.fill")
Text("Projects")
}
}
一旦我删除 ContentView 中的 .environment() 参数,应用程序将崩溃,因为没有加载上下文?!
错误信息是Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x804795e0>
。
ProjectsView.swift
struct ProjectsView: View {
@Environment(\.managedObjectContext) var managedObjectContext
[...]
}
但是,这又不是对的吗?那么,是什么导致了这里的错误?
在每个要访问 managedObjectContext 的视图中,您需要像这样声明它:
@Environment(\.managedObjectContext) var context: NSManagedObjectContext
您无需在浏览量上设置它,它会为您传递。并且不要忘记在这些文件中也导入 CoreData。
我能够通过修复 HostingController
并确保在构建视图之前设置 CoreData 堆栈来解决这个问题。首先,让我们确保 CoreData 堆栈已准备就绪。在 ExtensionDelegate
:
class ExtensionDelegate: NSObject, WKExtensionDelegate {
let persistentContainer = NSPersistentContainer(name: "Haha")
func applicationDidFinishLaunching() {
persistentContainer.loadPersistentStores(completionHandler: { (storeDescription, error) in
// handle this
})
}
}
当这个 属性 是 lazy
时我遇到了麻烦,所以我明确地设置了它。如果您 运行 遇到计时问题,请 loadPersistentStores
使用信号量进行同步调用以进行调试,然后弄清楚如何延迟 nib 实例化,直到稍后调用闭包。
接下来,让我们通过引用常量视图上下文来修复 HostingController
。 WKHostingController
是对象,不是结构。所以现在我们有:
class HostingController: WKHostingController<AnyView> {
private(set) var context: NSManagedObjectContext!
override func awake(withContext context: Any?) {
self.context = (WKExtension.shared().delegate as! ExtensionDelegate).persistentContainer.viewContext
}
override var body: AnyView {
return AnyView(ContentView().environment(\.managedObjectContext, context))
}
}
现在,任何子视图都应该可以访问 MOC。以下现在对我有用:
struct ContentView: View {
@Environment(\.managedObjectContext) var moc: NSManagedObjectContext
var body: some View {
VStack {
Text("\(moc)")
SubView()
}
}
}
struct SubView: View {
@Environment(\.managedObjectContext) var moc: NSManagedObjectContext
var body: some View {
Text("\(moc)")
.foregroundColor(.red)
}
}
您应该看到上面白色和下面红色的 MOC 地址,没有 在 SubView
上调用 .environment
。
我想开始使用 Core Data 和 SwiftUI,因此使用最新的 Xcode 11.1 GM 创建了一个新的 watchOS 项目。
然后,我从一个新的 iOS 项目(启用了核心数据)中复制了 persistentContainer
和 saveContext
,以获得核心数据功能。
之后我将HostingController
修改为returnAnyView
并在环境中设置变量
class HostingController: WKHostingController<AnyView> {
override var body: AnyView {
let managedObjectContext = (WKExtension.shared().delegate as! ExtensionDelegate).persistentContainer.viewContext
return AnyView(ContentView().environment(\.managedObjectContext, managedObjectContext))
}
}
现在我可以访问 ContentView
、 中的上下文,但不能访问其子视图。
但这不是它的本意吗?据我所知,所有子视图都应该从其父视图继承其环境,对吗?
现在,要在其子视图中访问它,我只需再次设置环境变量,如下所示:
ContentView.swift
NavigationLink(destination: ProjectsView().environment(\.managedObjectContext, managedObjectContext)) {
HStack {
Image(systemName: "folder.fill")
Text("Projects")
}
}
一旦我删除 ContentView 中的 .environment() 参数,应用程序将崩溃,因为没有加载上下文?!
错误信息是Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x804795e0>
。
ProjectsView.swift
struct ProjectsView: View {
@Environment(\.managedObjectContext) var managedObjectContext
[...]
}
但是,这又不是对的吗?那么,是什么导致了这里的错误?
在每个要访问 managedObjectContext 的视图中,您需要像这样声明它:
@Environment(\.managedObjectContext) var context: NSManagedObjectContext
您无需在浏览量上设置它,它会为您传递。并且不要忘记在这些文件中也导入 CoreData。
我能够通过修复 HostingController
并确保在构建视图之前设置 CoreData 堆栈来解决这个问题。首先,让我们确保 CoreData 堆栈已准备就绪。在 ExtensionDelegate
:
class ExtensionDelegate: NSObject, WKExtensionDelegate {
let persistentContainer = NSPersistentContainer(name: "Haha")
func applicationDidFinishLaunching() {
persistentContainer.loadPersistentStores(completionHandler: { (storeDescription, error) in
// handle this
})
}
}
当这个 属性 是 lazy
时我遇到了麻烦,所以我明确地设置了它。如果您 运行 遇到计时问题,请 loadPersistentStores
使用信号量进行同步调用以进行调试,然后弄清楚如何延迟 nib 实例化,直到稍后调用闭包。
接下来,让我们通过引用常量视图上下文来修复 HostingController
。 WKHostingController
是对象,不是结构。所以现在我们有:
class HostingController: WKHostingController<AnyView> {
private(set) var context: NSManagedObjectContext!
override func awake(withContext context: Any?) {
self.context = (WKExtension.shared().delegate as! ExtensionDelegate).persistentContainer.viewContext
}
override var body: AnyView {
return AnyView(ContentView().environment(\.managedObjectContext, context))
}
}
现在,任何子视图都应该可以访问 MOC。以下现在对我有用:
struct ContentView: View {
@Environment(\.managedObjectContext) var moc: NSManagedObjectContext
var body: some View {
VStack {
Text("\(moc)")
SubView()
}
}
}
struct SubView: View {
@Environment(\.managedObjectContext) var moc: NSManagedObjectContext
var body: some View {
Text("\(moc)")
.foregroundColor(.red)
}
}
您应该看到上面白色和下面红色的 MOC 地址,没有 在 SubView
上调用 .environment
。