如何在UIRepresentable封装的MapKit中添加网络获取的大量标注
核心调整思路
- 数据直接存在你已有的
DataModel中即可,只需给locations属性添加@Published修饰,网络请求更新数据后会自动触发UI刷新 - 标注更新逻辑放在
updateUIView方法中实现,这是UIViewRepresentable接收SwiftUI状态变化的标准回调入口 - 用
addAnnotations批量添加标注,配合系统自带的聚合能力优化800个标注的渲染性能
第一步:修改DataModel支持状态通知
确保网络请求更新位置数据后能通知视图刷新:
class DataModel: ObservableObject { // 加@Published修饰,数据变更时自动推送更新 @Published var locations: [Location] = [] // 你的网络请求逻辑示例 func requestLocationData() { // 发起网络请求,解析返回的位置数组 URLSession.shared.dataTask(with: URL(string: "你的接口地址")!) { [weak self] data, _, error in guard let data = data, error == nil, let list = try? JSONDecoder().decode([Location].self, from: data) else { return } DispatchQueue.main.async { // 赋值后自动触发UIMapView更新 self?.locations = list } }.resume() } }
第二步:修改UIMapView实现批量标注更新
struct UIMapView: UIViewRepresentable { @EnvironmentObject var dataModel: DataModel @EnvironmentObject var mapViewModel: MapViewModel func makeCoordinator() -> Coordinator { Coordinator() } func makeUIView(context: Context) -> MKMapView { let view = mapViewModel.mapView drawOverlayRing(view: view) view.delegate = context.coordinator // 提前注册标注视图,提升复用性能 view.register(MKPinAnnotationView.self, forAnnotationViewWithReuseIdentifier: "pinAnnotation") view.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: "clusterAnnotation") return view } func updateUIView(_ uiView: MKMapView, context: Context) { // 先清理旧的自定义标注,保留用户定位标注 uiView.annotations.forEach { annotation in guard !(annotation is MKUserLocation) else { return } uiView.removeAnnotation(annotation) } // 批量生成标注 let annotations = dataModel.locations.map { location in let annotation = MKPointAnnotation() annotation.title = location.title annotation.coordinate = .init(latitude: location.latitude, longitude: location.longitude) return annotation } // 批量添加标注,性能远高于循环单个添加 uiView.addAnnotations(annotations) } class Coordinator: NSObject, MKMapViewDelegate { func mapView(_ map: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { // 跳过用户位置标注 if annotation is MKUserLocation { return nil } // 处理聚合标注视图 if let cluster = annotation as? MKClusterAnnotation { let clusterView = map.dequeueReusableAnnotationView(withIdentifier: "clusterAnnotation") as? MKMarkerAnnotationView ?? .init(annotation: annotation, reuseIdentifier: "clusterAnnotation") clusterView.glyphText = "\(cluster.memberAnnotations.count)" clusterView.markerTintColor = .systemBlue return clusterView } // 处理普通标注视图 let identifier = "pinAnnotation" guard let pinView = map.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView else { let pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) pinView.canShowCallout = true // 开启自动聚合,相同id的标注会自动聚合 pinView.clusteringIdentifier = "locationGroup" return pinView } pinView.annotation = annotation return pinView } } // 保留你原有的绘制叠加层逻辑 func drawOverlayRing(view: MKMapView) { // 原有实现不变 } }
性能优化说明
- 开启
clusteringIdentifier后系统会自动根据地图缩放级别聚合标注,缩小地图时显示聚合点、放大时拆分,大幅降低渲染压力 - 800个标注用批量添加的方式不会出现卡顿,配合MKAnnotationView的复用机制,内存占用会维持在很低的水平
- 无需手动管理标注生命周期,网络请求返回数据后只需赋值给
DataModel.locations即可自动完成标注刷新
内容的提问来源于stack exchange,提问作者markb
相关产品推荐
相关产品推荐

