NOTE This is a question about best practices when coding.
After completing the challenge tasks, I noticed that my ContentView had a ZStack which in turn displays my CompleteMapView with another ZStack. See below:
ContentView:
struct ContentView: View {
@State private var isUnlocked = false
var body: some View {
Group {
if isUnlocked {
CompleteMapView()
} else {
UnlockButton(isUnlocked: $isUnlocked)
}
}
}
}
CompleteMapView:
var body: some View {
ZStack {
MapView(centerCoordinate: $centerCoordinate, selectedPlace: $selectedPlace, showingPlaceDetails: $showingPlaceDetails, annotations: locations)
.edgesIgnoringSafeArea(.all)
.alert(isPresented: $showingPlaceDetails) {
Alert(title: Text(selectedPlace?.title ?? "Unknown"), message: Text(selectedPlace?.subtitle ?? "Missing place information."), primaryButton: .default(Text("OK")), secondaryButton: .default(Text("Edit")) {
self.showingEditScreen = true
})
}
Circle()
.fill(Color.blue.opacity(0.3))
//.opacity(0.3)
.frame(width: 32, height: 32)
VStack {
Spacer()
HStack {
Spacer()
Button(action: {
let newLocation = CodableMKPointAnnotation()
newLocation.coordinate = self.centerCoordinate
newLocation.title = "Example location"
self.locations.append(newLocation)
self.selectedPlace = newLocation
self.showingEditScreen = true
}) {
Image(systemName: "plus")
.padding()
.background((Color.black.opacity(0.75)))
.foregroundColor(.white)
.font(.title)
.clipShape(Circle())
.padding(.trailing)
}
}
}
}
.sheet(isPresented: $showingEditScreen, onDismiss: saveData) {
if self.selectedPlace != nil {
EditView(placemark: self.selectedPlace!)
}
}
.onAppear(perform: loadData)
}
I thought I'd be smart and change the CompleteMapView from a ZStack to a Group.
The app appears to launch and run just fine... but I noticed that in the terminal, I get the following print...
Data successfully loaded from DocumentsDirectory.
Data successfully loaded from DocumentsDirectory.
Data successfully loaded from DocumentsDirectory.
.onAppear(peform: loadData) is now being run 3 times, apparently being run for each of the 3 Views inside my Group (MapView, Circle, and VStack). I tested adding another View inside Group and sure enough, it adds a 4th call to loadData.
Switching it back to a ZStack makes it work. Also, just moving the .onAppear inside the group and attaching it to the MapView seems to work.
I'm not sure what the best coding practice is. Those elements are designed to be shown over each other in a particular order, so grouping them with Group could lead to trouble down the road if CompleteMapView gets called in anything other than a ZStack, right?
This all started because I found it redundant showing a ZStack (CompleteMapView) inside a ZStack (ContentView).
Any thoughts on best practice would be appreciated.