I am using a class conforming to ObservableObject
to store locations. I have used @AppStorage
to persist an array of locations selected by a user.
class SavedLocations: ObservableObject {
@AppStorage("Locations") var all = [Location]()
func deleteLocation(at offsets: IndexSet) {
all.remove(atOffsets: offsets)
}
}
The class above is first instantiated using @StateObject
in a menu that displays chosen locations (if any) and a sheet which can be used to search for new locations to add.
struct LocationView: View {
@Environment(\.dismiss) var dismiss
@ObservedObject var networking: Networking
@StateObject var savedLocations = SavedLocations()
@State private var showingSheet = false
var body: some View {
NavigationView{
VStack {
// the list of all location, not always refreshed when updated using LocationSearch sheet presentation
List {
ForEach(savedLocations.all, id: \.self) { saved in
Button(saved.name) {
// use the selected location
dismiss()
}
}
.onDelete(perform: savedLocations.deleteLocation)
}
}
.sheet(isPresented: $showingSheet) {
LocationSearch(networking: networking)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button{
showingSheet.toggle()
} label: {
Label("New Location", systemImage: "plus")
}
}
}
.navigationTitle("Locations")
}
}
}
If a user searches for a location, they are presented with a list of locations as shown below:
struct LocationSearch: View {
@Environment(\.dismiss) var dismiss
@StateObject var locationService = LocationService()
@ObservedObject var networking: Networking
@ObservedObject var savedLocations = SavedLocations()
@State var showAlert = false
var body: some View{
Form {
...
Section {
List {
ForEach(locationService.searchResults, id: \.self) { completionResult in
Button("\(completionResult.city), \(completionResult.country)") {
networking.getCoordinate(addressString: completionResult.city) { coordinates, error in
if error == nil {
networking.lastLocation = CLLocation(latitude: coordinates.latitude, longitude: coordinates.longitude)
DispatchQueue.main.async() {
let newLocation = Location(name: completionResult.city)
// UPDATES not always reflected when sheet is dismissed
savedLocations.all.append(newLocation)
savedLocations.all = savedLocations.all.unique()
dismiss()
}
} else {
print("Error setting custom location: \(String(describing: error))")
showAlert.toggle()
}
}
}
}
}
}
}
}
}
The problem is that upon dismissing the sheet used to search for and add locations, the new location does not always immediately appear in the list of all locations. Usually it does appear immediately after the search sheet is dismissed, but occasionally it is necessary to dismiss both sheets and trigger a new instance of the sheet containing the list of all locations.
I based my approach off of this post.
You are creating a new instance of SavedLocations when you do this:
@ObservedObject var savedLocations = SavedLocations()
You likely mean to do:
@ObservedObject var savedLocations: SavedLocations
and pass the existing SavedLocations
into LocationSearch