在Swift中,这会在运行时崩溃:
class EmptyData: BindableObject {
let didChange = PassthroughSubject<EmptyData, Never>()
}
struct RandomView : View {
@EnvironmentObject var emptyData: EmptyData
@EnvironmentObject var emptyData2: EmptyData
var body: some View {
Text("Hello World!")
}
}
和SceneDelegate.swift
中的
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let window = UIWindow(frame: UIScreen.main.bounds)
// The emptyData variables are not initialized as seen below
window.rootViewController = UIHostingController(rootView: RandomView())
self.window = window
window.makeKeyAndVisible()
}
线程1:EXC_BAD_INSTRUCTION(代码= EXC_I386_INVOP,子代码= 0x0)
解决问题并不难,但是很奇怪:
window.rootViewController = UIHostingController(rootView: RandomView().environmentObject(EmptyData()))
那么这是怎么回事?我通过了EmptyData()
,SwiftUI决定emptyData
和emptyData2
都应使用相同的对象引用进行初始化?我还可以传递RandomView
实例中甚至不存在为变量的其他环境对象:
window.rootViewController = UIHostingController(rootView: RandomView().environmentObject(EmptyData()).environmentObject(SomeData()))
尽管SomeData()
实例中未在任何地方使用RandomView()
,但SwiftUI还是很高兴地运行,在我看来应该会触发编译时错误。
为什么在初始化对象时在编译时允许未初始化的值而无需对其进行初始化,为什么我们可以自由地传递环境实例而无需对其进行任何处理?在我看来有点像Javascript,我喜欢Swift中强大的静态安全键入...我看不到为什么明智的成员初始化程序只是生成一个将环境变量作为参数的初始化程序。
答案 0 :(得分:1)
EnvironmentObject
属性委托具有一个init()
方法,该方法不带任何参数,并且为包装的属性提供了隐式初始化
@EnvironmentObject var emptyData: EmptyData
@EnvironmentObject var emptyData2: EmptyData
(Modern Swift API Design视频中大约在28:10对此进行了解释)。因此,这些(非可选)属性不需要(显式)初始值。
文档还指出EnvironmentObject
是(强调)
...一个动态视图属性,该属性使用可转换对象的祖先视图提供的可绑定对象来使当前视图无效。
您必须通过调用其环境对象(_ :)方法在祖先视图上设置模型对象。
这就是我的理解:
EmptyData
的实例),则将属性初始化为此对象。 SomeData
中未使用的环境对象(在您的情况下为RandomView
的实例)并不是错误。 / li>
答案 1 :(得分:1)
什么是@EnvironmentObject?
一个链接的View属性,该属性读取由 祖先
因此,可以从祖先向儿童提供环境道具,而不必从其直接父母那里获得。 这样,请看下面的代码片段,因为RandomViewGrandParent将所需的Env对象注入到环境中,所以如果RandomViewParent的子代需要相同的Env obj,则RandomViewParent无需执行任何操作。 RandomViewParent可以仅启动视图,而无需再次传递env obj。
BindableObject
然后回答您的另一个问题-
我通过EmptyData(),SwiftUI决定emptyData和 应该使用相同的对象引用来初始化emptyData2?
那是因为EnvironmentObject符合BindableObject,而BindableObject的didChange是Publisher,所以我认为它认为emptyData和emptyData2都希望订阅相同的事件/值,因此对两者使用相同的引用。