SwiftUI MapKit - MapAnnotation - Publishing changes from within view updates is not allowed, this will cause undefined behavior.

So I'm trying to use MapKit in a SwiftUI project targeting iOS/iPadOS. MapKit is obviously pretty limited in SwiftUI, but I've been getting warnings trying to set up basic annotations for the user to interact with.

When I use a basic MapMarker everything is fine (although it's hard to do anything with it), but whenever I do anything with MapAnnotation, I get this warning in Xcode (14.0.1) whenever I move the map around:

[SwiftUI] Publishing changes from within view updates is not allowed, this will cause undefined behavior.

I'm no SwiftUI expert, and I get how to fix this issue when binding in something like a sheet, but I don't see how what I'm doing with MapAnnotation should be causing this.

It looks like a bug to me, possibly complaining about the $region binding, but maybe I'm wrong? Am I doing something wrong or is this a bug?

Below is some sample code that reproduces this easily for me (just launch an app with the below code and then drag the map around to see the constant warnings in Xcode). It's mostly an example from here: https://www.hackingwithswift.com/books/ios-swiftui/integrating-mapkit-with-swiftui

import SwiftUI
import MapKit

struct Location: Identifiable {
    let id = UUID()
    let name: String
    let coordinate: CLLocationCoordinate2D
}

struct ContentView: View {
    @State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.5, longitude: -0.12), span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2))

    let locations = [
        Location(name: "Buckingham Palace", coordinate: CLLocationCoordinate2D(latitude: 51.501, longitude: -0.141)),
        Location(name: "Tower of London", coordinate: CLLocationCoordinate2D(latitude: 51.508, longitude: -0.076))
    ]

    var body: some View {
        Map(coordinateRegion: $region, annotationItems: locations) { location in
            MapAnnotation(coordinate: location.coordinate) {
                Circle()
                    .stroke(.red, lineWidth: 3)
                    .frame(width: 44, height: 44)
            }
        }
        .navigationTitle("Map")
        .edgesIgnoringSafeArea(.all)
    }
}

This issue started in XCode 14 (Beta 5?) and iOS16. Nobody knows what it is, why it happens, and if it is an issue that might cause crashes or other side effects or simply a bug in XCode 14 - iOS 16. There is no advice from apple on properly handling this warning and it is not only MapKit-related (although I encountered it for the first time while playing with MapKit) but happens everywhere where you bind to a published property. Some have figured it is related to view animations (MapKit moving the map, a button fading on click, etc.). So an ugly workaround is to wrap the access to this property with a timer that delays actions until the animation ends.

OK thanks @MartinMajewski

Yeah, in the example above, there's nothing actually using a binding other than $region, but a binding is required for the coordinateRegion on the Map initializer. And it's also just a plain @State property, so nothing even that fancy.

Not to confuse the issue, but there are some other areas (other than with the MapKit issue above) where I've seen this same warning that make sense to me and I've eliminated the errors in my code. Here is a YouTube video that made my understanding of it a little more clear: https://www.youtube.com/watch?v=3a7tuhVpoTQ

I'm going to assume for now with the MapKit example it's a bug. I just submitted it as an issue in Feedback Assistant in case that helps.

So glad to find this thread. I'm experiencing the same issue with the Apple SwiftUI Tutorials (https://developer.apple.com/tutorials/swiftui). I'm using Xcode 14.1. At first I thought I had made a mistake while going through the tutorial, but found the same warning ("Publishing changes from within view updates is not allowed, this will cause undefined behavior.") when running the completed code provided with the tutorial. In this example it seems related to MapKit. Frustrating, but good to know I'm not alone. :-)

Ok, it is still an issue! I'm using Xcode 14.2. and my target is iOS 16, SwiftUI-4

Now the main question is:

Can we use it in production?

We really need some guidance from Apple on this. Before I refactor huge parts of our app, I would like to know if it is necessary, or if this is a bug.

I've got the same problem. Like the OP found, MapMarker is OK, MapAnnotation isn't, no matter how simple (even with nothing but an EmptyView). Also, if I click on one of the purple triangles XCode claims it's caused by the @main annotation before my App definition.

I've tried eliminating all @State vars from my View, and wrapped my MKCoordinateRegion in a simple class to make it mutable, and passed a simple binding to the Map constructor:

Binding(
    get: {coordinateRegionHolder.coordinateRegion},
    set: { region in
        self.coordinateRegionHolder.coordinateRegion = region
     })

I'm still getting those error messages. I think something in MapAnnotation is incorrectly modifying some internal state during update, because it seems less likely to me that XCode would misdetect it if it isn't happening. We're not supposed to make our own custom annotations by implementing MapAnnotationProtocol (why not?), so it looks like UIViewRepresentable is the only way we can be confident of reliably displaying a map with custom annotations.

Seeing this in Xcode 14.1 and iOS 16! Eagerly awaiting guidance from Apple.

This is a bug and we need Apple to fix it ASAP. Thanks.

Unfortunately this issue still exists. The combination of Map() and MapAnnotation() causes it. Switching out the annotations with MapMarker() removes the runtime errors, but unfortunately isn't suited for my uses case. It might help someone else though.

The purple runtime error pops up quite a bit. And most of the time it's valid: you're updating a @Published var from within the view you display that same @Published var. Which is bad. But I don't see this cause at all with the MapAnnotation implementation, something else must be triggering this.

I think this is a bug, same issue here !

Just an update for anyone reading here -- my Feedback Assistant bug report for this issue now says "Potential fix identified - For a future OS update"

Also, one other note because I saw mention of UIViewRepresentable. I'm currently using that solution in an app, actually, because the native SwiftUI maps are so limited. I get the same warning when I strip it down to just the essentials with makeUIView creating an MKMapView so it doesn't completely resolve the issue to go that route, unless I'm missing something. However, I haven't noticed any incorrect behavior (although I definitely have to handle threading in updateUIView)

Check Map's initializer called when you move Map's region.

This is simple example


class PlaceViewModel: ObservableObject {
    var region: MKCoordinateRegion = .seoul
    @Published var places: [Place] = []
}

struct PlaceView: View {
    @StateObject var viewModel = PlaceViewModel()

    var body: some View {
        ZStack(alignment: .top) {
            Map(
                coordinateRegion: $viewModel.region,
                annotationItems: viewModel.places
            ) { item in
                MapAnnotation(coordinate: item.location) {
                    Text(item.title)
                }
            }
        }
    }
}

I still have this issue. When working with Map() and MapAnnotation(), I get swamped by console prints and purple warnings. Apple please provide a fix or advice!

For what it's worth, my Feedback about this bug (FB11723508) which previously said "Potential fix identified - For a future OS update" has been changed back to "Open" so I'm not sure if it's being worked on at Apple at the moment.

SwiftUI MapKit - MapAnnotation - Publishing changes from within view updates is not allowed, this will cause undefined behavior.
 
 
Q