Function Calls in Swiftui

I've been asking a lot of questions so I promise I will take at least a week off after this. I am trying to update 2 arrays. Can't seem to figure out where the function call findLocations() will work.

We encourage questions that are just about using Apple frameworks like SwiftUI to be asked on the Apple developer forums.

2 Likes

I'll answer the part that is related to Swift syntax, and then a little tangent about SwiftUI. However, it should not be treated as a signal/encouragement to post SwiftUI related question on this forum. Questions purely about SwiftUI should still be in Apple Dev's forum.


First, you need to notice that body is a computed property, or specifically read-only computed property. It is signified by the syntax:

var propertyName: PropertyType {
  // Function returning `Property Type`
}

with propertyName being body and PropertyType being some View. All in all, the thing inside bracket needs to return something of type some View. You may not noticed it because you rarely write return inside body. This is because most of the time, it is a function with single statement, which is returned. That is, it is a function with implicit return. So when you write:

var body: some View {
  VStack { ... }
}

Swift actually reads it as:

var body: some View {
  return VStack { ... }
}

Now, if you have more than one statement, like in this case (findLocations, and VStack), Swift will no longer insert the return for you. Making your function not returning anything, when it should return some View, hence the error. The error is a little cryptic partly because you're using opaque type some View, which requires you to return some value that conforms to View.

So it's an error that you're not returning anything in a computed property. Doubly so in a computed property with opaque return type.

So, since you're doing some computation, then return the VStack, what you need to do, is to add return that Swift no longer insert for you (because you now have more than one statement).

var body: some View {
  findLocation()
  return VStack { ... }
}

All-in-all blindly flailing around in hope of fixing the compiler error won't get very far. You need to figure out what the error is saying, then figure out whether 1) you're not using the syntax the way it's meant to be used, 2) you're misunderstanding what the code means, or 3) you're not understanding the contract (computed property needs to return value).


Some rant about SwiftUI since the *fix* above still won't be enough.

Now, simply adding return won't get it to work as expected because, remember, you do not mutate @State when computing body. EVER. And right now, you're mutating detailArray (a @State) and coordArray (another @State) inside findLocations, which is invoked within body property. Bad, bad things all around.

You need to ask, "when do I mutate/update these values?". The answer is (almost) never "when the view is being drawn". Rather

  • "when I first load up this view": for which you use onAppear,
  • "when something happens" like onDrag when user want to drag you item out for drag'n'drop, onTapGesture when user is tapping your screen, etc.

Or in this case:

  • "when a related data change": for which you'd pass it down from higher ups, and compute it together with the changed data.

Which is one thing you can do: whenever myLocations changes, sneak in the code that update detailArray and coordArray in that, most likely you have enough room for three* :flushed:. If it needs to be in the parent of the current view, just pass it down as a let variable.

* It's possible you want to cache the computation instead on recomputing it every time, which is a very non-trivial, if not advanced, technique.

3 Likes