Reputation: 441
By accident i added a modifier to my swift UI view without a leading point. And it compiled. And i can not wrap my head around why i did that. Here some example Code:
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(
destination: DetailView(),
label: {
Text("Goto Detail")
})
navigationTitle("ContentView")
}
}
}
struct DetailView: View {
var body: some View {
Text("Detail View")
.padding()
navigationTitle("Detail")
}
}
Somehow even stranger is that the first "wrong" modifier navigationTitle("ContentView")
does just nothing.
The second one navigationTitle("Detail")
lets the App crash when navigating to the View during runtime.
Similar to this is
struct DetailView: View {
var body: some View {
padding()
}
}
This View does compile but just crashes, if tried to shown with Previews. And it just can't be navigated to.
I would really expect this code to not even compile. Is somebody able to explain this?
Upvotes: 0
Views: 48
Reputation: 271175
If you refer to a method by its simple name (e.g. navigationTitle
), it's kind of like saying self.navigationTitle
:
struct DetailView: View {
var body: some View {
Text("Detail View")
.padding()
self.navigationTitle("Detail")
}
}
This is valid, because self
is also a View
, and that modifier is available on all View
s. It gives you a new view that is self
, but with a navigation title of Detail
. And you are using both of them as the body
. Normally you can't return multiple things from a property, but it works here because the body
protocol requirement is marked @ViewBuilder
.
Of course, you are using self
as the self's body, and you can't have self referencing views, so it fails at runtime.
If you add self.
to the other cases, it's pretty easy to understand why they compile:
struct DetailView: View {
var body: some View {
self.padding() // self conforms to View, so you can apply padding()
// padding() returns another View, so it's valid to return here
}
}
"The body of DetailView
is itself, but with some padding."
NavigationView {
NavigationLink(
destination: DetailView(),
label: {
Text("Goto Detail")
})
self.navigationTitle("ContentView")
}
"The navigation view consists of a navigation link, and ContentView
itself (what self
means here) with a navigation title of ContentView
"
This doesn't crash immediately either because NavigationView
's initialiser is smart enough to ignore the junk ContentView
that you have given it, or because there is an extra level of indirect-ness to the self-referencing. I don't think we can know exactly why it crashes/doesn't crash immediately, until SwiftUI becomes open source.
Upvotes: 2