Oh good, I’m glad you found this issue. It is worse than that, though. Figure out which location in your list is the last one, then go to the map and tap it so the annotation is showing. Now go back to the list and delete a location before the last one. Now go back to the map, where the last one is still showing, and tap it to edit. It should bust. (The list view is sorted by category and description, making it harder to test, unless you keep the same category for all, and label them A, B, C, or something).
When you delete a location from the list, the index of every location after it changes. The index of the last one goes down -1. The index stored in the annotation button tag is not only the wrong one, but is no longer a valid one. When you tap the button, you get nothing, and it breaks. (This doesn’t happen if you use the original updateLocations every time, as it just clears out all the annotations and loads them up again).
I think if you look at your code, you will realize you are using the sets that were passed in userInfo. So you might as well just use them directly. Then you don’t need to rerun the fetch.
if self.isViewLoaded, let dictionary = notification.userInfo {
if let insertLocations = dictionary["inserted"] as? Set<Location> {
for location in insertLocations {
self.locations.append(location)
self.mapView.addAnnotation(location)
print("*** map added a location")
}
}
You can just get the sets and process the locations in them. A set is a lot like a list, same syntax to loop through. You could still use your nice enum for the state.
The deleteLocations loop will be very similar, except you also need the index of the location to remove it from the locations list:
if let index = self.locations.index(of: location) {
Updated ones are interesting. What people tend to forget is that your Locations are MKAnnotations. Unless the coordinates of the location changes, there is nothing that needs to be updated. Even then, I think the map display would pick up the change. There is not much point in removing them and adding them again - they are already there.
The visible annotation view, if there is one, is different. It is a view built from the location, so it should be updated. In my opinion, it should stay selected. So you do a bit of code to refresh the selected annotation if there is one:
for location in self.mapView.selectedAnnotations {
if let view = self.mapView.view(for: location), view.isSelected {
self.mapView.deselectAnnotation(location, animated: false)
self.mapView.selectAnnotation(location, animated: false)
print("*** map updated a selected callout")
}
}
selectedAnnotations is an array, even though there is only ever 0 or 1 annotation in it. So we do a for loop anyway. (Maybe iOS 27 will support multiple selected annotations?).
The refresh causes it to rebuild the view for the annotation, so it gets the correct index into the button tag. It also will display your edit if you changed the title or category - even if you edited it from the list tab, not the map tab. It’s all wired up!