SwiftUI中MapAnnotation触发视图更新报错问题求助
解决SwiftUI MapAnnotation触发「Publishing changes from within view updates」报错问题
使用MapAnnotation时会弹出报错:[SwiftUI] Publishing changes from within view updates is not allowed, this will cause undefined behavior.,但替换成MapPin则无此问题。需要保留MapAnnotation(支持点击交互,iOS 17的Marker也存在类似报错情况),求可行的解决方法。
现有代码
自定义Annotation结构
struct MyAnnotation: Identifiable { let id = UUID() let name: String let coordinate: CLLocationCoordinate2D }
ViewModel代码
extension CLLocationCoordinate2D { static let ch = CLLocationCoordinate2D(latitude: 43.653734011477184, longitude: -79.38415146943686) static let rc = CLLocationCoordinate2D(latitude: 43.64190399683823, longitude: -79.38917588924176) static let sba = CLLocationCoordinate2D(latitude: 43.64358280036363, longitude: -79.37910987946465) } class AnnotationViewModel: NSObject, ObservableObject { @Published var annotations = [ MyAnnotation(name: "CITY HALL", coordinate: .ch), MyAnnotation(name: "ROGERS CENTER", coordinate: .rc), MyAnnotation(name: "SCOTIABANK ARENA", coordinate: .sba) ] }
视图代码
struct ContentView: View { @StateObject var annotationViewModel = AnnotationViewModel() @State var region = MKCoordinateRegion(center: .ch, span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)) var body: some View { Map(coordinateRegion: $region, annotationItems: annotationViewModel.annotations) { // MapPin(coordinate: $0.coordinate) 无报错,但不支持点击 MapAnnotation(coordinate: $0.coordinate) { Image(systemName: "t.circle.fill") } } } }
解决方案
你提到的相关方案完全适用,核心是切断视图更新周期与@Published变量的直接绑定,避免在视图渲染时触发不必要的发布通知。以下是针对你代码的具体修改方式:
方式一:静态数据移除@Published(无需动态更新时用)
如果标注数据不需要动态修改,直接去掉@Published修饰符——@StateObject已经能保证ViewModel的生命周期,静态数据不需要发布更新通知:
class AnnotationViewModel: NSObject, ObservableObject { var annotations = [ MyAnnotation(name: "CITY HALL", coordinate: .ch), MyAnnotation(name: "ROGERS CENTER", coordinate: .rc), MyAnnotation(name: "SCOTIABANK ARENA", coordinate: .sba) ] }
方式二:映射数据断开直接绑定(需要动态更新时用)
如果需要保留标注数据的动态更新能力,在视图中对annotations做一次无意义的映射转换,断开与@Published集合的直接引用:
struct ContentView: View { @StateObject var annotationViewModel = AnnotationViewModel() @State var region = MKCoordinateRegion(center: .ch, span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)) var body: some View { let mappedAnnotations = annotationViewModel.annotations.map { $0 } Map(coordinateRegion: $region, annotationItems: mappedAnnotations) { MapAnnotation(coordinate: $0.coordinate) { Image(systemName: "t.circle.fill") } } } }
方式三:iOS 17+ 改用Marker组件(推荐)
如果项目支持iOS 17及以上版本,直接使用官方新推出的Marker组件,它天然支持点击交互,且不会触发该报错:
Map(coordinateRegion: $region, annotationItems: annotationViewModel.annotations) { item in Marker(item.name, coordinate: item.coordinate) .tint(.red) }
内容的提问来源于stack exchange,提问作者Rhythmus
相关产品推荐
相关产品推荐

