In Swift, this crashes at runtime:
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!")
}
}
and in the 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()
}
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
Fixing the problem isn't that hard, but rather strange:
window.rootViewController = UIHostingController(rootView: RandomView().environmentObject(EmptyData()))
So what's happening here? I pass EmptyData() and SwiftUI decides that both emptyData and emptyData2 should be initialized with the same object reference? I can pass also other environmentobjects that do not even exists as variables in the RandomView instance:
window.rootViewController = UIHostingController(rootView: RandomView().environmentObject(EmptyData()).environmentObject(SomeData()))
And SwiftUI just happily run, although SomeData() isn't used anywhere in the instance of RandomView() and should trigger a compile time error in my opinion.
Why are uninitialized values permitted at compile time without initializing them when initializing the object and why are we free to pass environment instances without doing anything with them? Looks a bit like Javascript to me, I loved the strong static safe typing in Swift... I don't see right away why the member-wise initializer just generates an initializer which takes the environment variables as it's parameter.