How does @EnvironmentObject get around Swift initializer requirements?

How does a SwiftUI View with a non-nil property decorated with @EnvironmentObject get around that property not being set during initialization? I know .environmentObject() does set the value but the Swift rules as I understand them would not allow that. I encountered this with the userData property of LandmarkList from the SwiftUI Tutorial:

https://developer.apple.com/tutorials/swiftui

On Twitter I was told: "Think of it as an implicitly unwrapped optional. It’s just initialized to nil until the value is available."

I agree this is the behavior I'm observing but I don't understand how the language rules are being manipulated to accomplish this. Normally a non nil property would have to be passed in through the initializer.

In my testings going through the Landmark tutorial, when I removed the call to .environmentObject() below I was surprised I did not get a compiler warning but instead a runtime error which feels very unSwift-like.

Code Block
window.rootViewController = UIHostingController(
rootView: LandmarkList()
.environmentObject(UserData())
)


Thanks for any help or pointers.

Accepted Reply

To understand the behavior of @EnvironmentObject in detail, you need to know how property wrappers work in Swift.
SE-0258Property Wrappers

If you declare a property with @EnvironmentObject like this:
Code Block
    @EnvironmentObject var userData: UserData

it is translated by the Swift compiler and generates some code equivalent to the following:
Code Block
var _userData: EnvironmentObject<UserData> = EnvironmentObject<UserData>()
var userData: UserData {
get {_userData.wrappedValue}
}


So, the property userData actually is a computed property which does not need initialization.
And implicitly declared stored property is implicitly initialized with the right wrapping struct.

Swift rules applies to these translated properties, the language rules are not manipulated.

Replies

To understand the behavior of @EnvironmentObject in detail, you need to know how property wrappers work in Swift.
SE-0258Property Wrappers

If you declare a property with @EnvironmentObject like this:
Code Block
    @EnvironmentObject var userData: UserData

it is translated by the Swift compiler and generates some code equivalent to the following:
Code Block
var _userData: EnvironmentObject<UserData> = EnvironmentObject<UserData>()
var userData: UserData {
get {_userData.wrappedValue}
}


So, the property userData actually is a computed property which does not need initialization.
And implicitly declared stored property is implicitly initialized with the right wrapping struct.

Swift rules applies to these translated properties, the language rules are not manipulated.
Thanks so much for the explanation.

I would argue this @EnvironmentObject behavior is a runaround, a legal loophole, to the overall spirit of type safety and expression for the benefit of compiler time error checking in Swift -- but the question was more how than why, so I appreciate your help.